Неожиданный вывод по конвейерной функции - PullRequest
2 голосов
/ 07 июля 2019

Я пытаюсь эмулировать монаду Maybe на PHP, и не могу понять вывод написанной мной функции piped.

Код основан на статье Эрика Эллиотта .

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

Может ли какая-нибудь яркая душа осветить меня?

1 Ответ

1 голос
/ 07 июля 2019

Прежде всего, ожидаемый результат не должен быть примерно таким:

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 вы получаете нулевое значение, поэтому каждый вызов метода 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;

...