<?php
namespace Endo\Data;
use Endo\Core\Module;
use Endo\Lib\Strings;
use Endo\Typeclass\IMonad;
/**
* Either Monad
*/
class Either extends Module implements IMonad {
private $value;
private $isRight;
private function __construct($value, $isRight) {
$this->value = $value;
$this->isRight = $isRight;
}
protected static function __left($value): Either {
return new Either($value, false);
}
protected static function __right($value): Either {
return new Either($value, true);
}
public function map(callable $f): Either {
return $this->isRight ? self::right($f($this->value)) : $this;
}
public static function pure($a): Either {
return self::right($a);
}
public function apply($a): Either {
return $this->flatmap(function ($f) use ($a) {
return $a->map(function ($x) use ($f) {
return $f($x);
});
});
}
public function liftA2($a, $b): Either {
return $this->apply($a)->apply($b);
}
public function liftA3($a, $b, $c): Either {
return $this->apply($a)->apply($b)->apply($c);
}
public function liftA4($a, $b, $c, $d): Either {
return $this->apply($a)->apply($b)->apply($c)->apply($d);
}
public function liftA5($a, $b, $c, $d, $e): Either {
return $this->apply($a)->apply($b)->apply($c)->apply($d)->apply($e);
}
public function liftA6($a, $b, $c, $d, $e, $f): Either {
return $this->apply($a)->apply($b)->apply($c)->apply($d)->apply($e)->apply($f);
}
public function liftA7($a, $b, $c, $d, $e, $f, $g): Either {
return $this->apply($a)->apply($b)->apply($c)->apply($d)->apply($e)->apply($f)->apply($g);
}
public function liftA8($a, $b, $c, $d, $e, $f, $g, $h): Either {
return $this->apply($a)->apply($b)->apply($c)->apply($d)->apply($e)->apply($f)->apply($g)->apply($h);
}
public function liftA9($a, $b, $c, $d, $e, $f, $g, $h, $i): Either {
return $this->apply($a)->apply($b)->apply($c)->apply($d)->apply($e)->apply($f)->apply($g)->apply($h)->apply($i);
}
public function flatmap(callable $f): Either {
return $this->isRight ? $f($this->value) : $this;
}
public function getValue() {
return $this->value;
}
public function match(callable $left, callable $right): void{
$this->isRight ? $right($this->getValue()) : $left($this->getValue());
}
public function isRight(): bool {
return $this->isRight;
}
protected static function __extract($eitherValue) {
return $eitherValue->getValue();
}
protected static function __fromOption($leftValue, Option $optionValue): Either {
return Option::isSome($optionValue) ? Either::right(Option::extract($optionValue)) : Either::left($leftValue);
}
public function __toString(): string {
return Strings::log($this->isRight ? "Either::right" : "Either::left", $this->value);
}
}
?>