<?php
require __DIR__ . '/lib.php';
$a = new Task(function($onSuccess, $onError) {
echo "a\n";
$onSuccess('a');
});
$b = new Task(function($onSuccess, $onError) {
echo "b\n";
$onSuccess('b');
});
$c = new Task(function($onSuccess, $onError) {
echo "c\n";
$onSuccess('c');
});
function concat($a) {
return function($b) use($a) {
return function($c) use($a, $b) {
return "$a$b$c";
};
};
}
$abc = ap(ap(map('concat', $a), $b), $c);
$abc->perform(function($result) {
echo "$result\n";
}, function($error) {
throw $error;
});
<?php
class Task {
private $perform;
public function __construct(callable $perform) {
$this->perform = $perform;
}
public function perform(callable $onSuccess, callable $onError) {
($this->perform)($onSuccess, $onError);
}
}
function map(callable $f, Task $a): Task {
return new Task(function($onSuccess, $onError) use($f, $a) {
$a->perform(function($aRes) use($f, $onSuccess) {
$onSuccess($f($aRes));
}, $onError);
});
}
// AKA <*>
function ap(Task $f, Task $a): Task {
return new Task(function($onSuccess, $onError) use($f, $a) {
$fVar = [null, false];
$aVar = [null, false];
$errored = false;
$f->perform(function($fRes) use($onSuccess, &$fVar, &$aVar) {
$fVar = [$fRes, true];
if ($aVar[1]) {
$onSuccess($fRes($aVar[0]));
}
}, function($err) use($onError, &$errored) {
if (!$errored) {
$errored = true;
$onError($err);
}
});
$a->perform(function($aRes) use($onSuccess, &$fVar, &$aVar) {
$aVar = [$aRes, true];
if ($fVar[1]) {
$onSuccess($fVar[0]($aRes));
}
}, function($err) use($onError, &$errored) {
if (!$errored) {
$errored = true;
$onError($err);
}
});
});
}