/**
  * 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');
 }
Example #2
0
/**
 * 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());
}