首页 > 解决方案 > 管道函数的意外输出

问题描述

我正在尝试在 PHP 上模拟 Maybe monad,但我无法理解我编写的管道函数的输出。

该代码的灵感来自Eric Elliott 的文章

php -v // PHP 7.2.19-0 ubuntu0.18.04

<?php   

function pipe_map(...$fns) {
    return function ($value) use ($fns) {

        return array_reduce($fns, function ($prev, $next) {

            return $prev->map($next);

        }, $value);
    };
};

class Maybe {
    private $value;

    public function __construct($value) {
        $this->value = $value;
    }

    private function doesExist() {
        return !empty($this->value);
    }

    public function map(callable $fn) {
        return $this->doesExist()
            ? new Maybe($fn($this->value))
            : new Maybe(NULL);
    }

    public function join() {
        return $this->value;
    }
}

$add1 = function ($value) {
    return $value + 1;
};

$trace = function ($label) {
    return function ($value) use ($label) {
        print_r($label . $value . "\n");
        return $value;
    };
};

$mult2 = function ($value) {
    return $value * 2;
};

$bad_result = function ($value) {
    echo "bad computation happens \n";
};

$maybe3 = new Maybe(3);

$result = pipe_map(
    $trace("Value is now: "),
    $add1,
    $trace("Value is now: "),
    $bad_result,
    $trace("Value is now: "),
    $add1,
    $trace("Value is now: "),
    $mult2,
    $trace("Value is now: ")
)($maybe3);


?>

预期的结果是这样的:

Value is now: 3
Value is now: 4
bad computation happens
Value is now: 
Value is now: 
Value is now: 

但我得到了:

Value is now: 3
Value is now: 4
bad computation happens 

我希望调用函数之后的$bad_result函数,但显然它们不是。

打印$result变量时,输出为:

print_r($result);

// Maybe Object
// (
//     [value:Maybe:private] => 
// )

var_dump($result->join());

// NULL

有什么明亮的灵魂可以照亮我吗?

标签: phpfunctional-programming

解决方案


首先,预期的结果不应该是这样的:

Value is now: 3
Value is now: 4
bad computation happens
Value is now: 
Value is now: 
Value is now: 

这是因为在$bad_result您调用add1闭包之后的下一次调用中,这将为您的输出添加 1 null + 1 = 1

所以预期的结果应该是这样的

Value is now: 3
Value is now: 4
bad computation happens
Value is now:
Value is now: 1
Value is now: 2

这一切都是因为你要回来new Maybe(NULL);

当您根本不调用它们时,您如何期望在错误计算之后执行回调?

请记住,从$bad_result回调开始,您将获得 null,因此对该map方法的每次调用将始终执行不调用任何内容的else语句。new Maybe(NULL);

相反,您需要Maybe($fn(null));确保每次迭代都调用您的可调用对象。


要获得确切的预期结果:

Value is now: 3
Value is now: 4
bad computation happens
Value is now: 
Value is now: 
Value is now: 

您将需要验证$value您的闭包,特别是add1闭包。

就像是 :

return !$value ? null : $value + 1;


推荐阅读