/** * Generic test to verify if a type obey the applicative laws. * * @param callable $assertEqual Asserting function (Applicative $a1, Applicative $a2, $message) * @param callable $pure Applicative "constructor" * @param Applicative $u Applicative f => f (a -> b) * @param Applicative $v Applicative f => f (a -> b) * @param Applicative $w Applicative f => f (a -> b) * @param callable $f (a -> b) * @param mixed $x Value to put into a applicative */ public static function test(callable $assertEqual, callable $pure, Applicative $u, Applicative $v, Applicative $w, callable $f, $x) { // identity: pure id <*> v = v $assertEqual($pure(f\identity)->ap($v), $v, 'identity'); // homomorphism: pure f <*> pure x = pure (f x) $assertEqual($pure($f)->ap($pure($x)), $pure($f($x)), 'homomorphism'); // interchange: u <*> pure x = pure ($ x) <*> u $assertEqual($u->ap($pure($x)), $pure(f\applicator($x))->ap($u), 'interchange'); // composition: pure (.) <*> u <*> v <*> w = u <*> (v <*> w) $compose = f\curryN(2, f\compose); $assertEqual($pure($compose)->ap($u)->ap($v)->ap($w), $u->ap($v->ap($w)), 'composition'); }
/** * liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c * * @param callable $transformation * @param Applicative $fa * @param Applicative $fb * * @return Applicative|\Closure */ function liftA2(callable $transformation = null, Applicative $fa = null, Applicative $fb = null) { return call_user_func_array(curryN(3, function (callable $transformation, Applicative $fa, Applicative $fb) { return $fa->map(function ($a) use($transformation) { return function ($b) use($a, $transformation) { return call_user_func($transformation, $a, $b); }; })->ap($fb); }), func_get_args()); }