Skip to content

Instantly share code, notes, and snippets.

@datibbaw
Last active December 23, 2015 07:58
Show Gist options
  • Save datibbaw/6604002 to your computer and use it in GitHub Desktop.
Save datibbaw/6604002 to your computer and use it in GitHub Desktop.
Playing with monads, inspired by Crockford's implementation: https://github.com/douglascrockford/monad/blob/master/monad.js
<?php
// A silly prototype chain until I can think of something better
class prototype
{
private $inherited;
private $instance;
public function __construct(prototype $prototype = null)
{
$this->inherited = $prototype;
$this->instance = [];
}
public function __set($name, $value)
{
$this->instance[$name] = $value;
}
public function __get($name)
{
if (array_key_exists($name, $this->instance)) {
return $this->instance[$name];
} else {
return $this->inherited->$name;
}
}
public function __call($name, $arguments)
{
return call_user_func_array($this->$name->bindTo($this), $arguments);
}
}
// Just a shell around a prototype chain
class monad extends prototype
{
}
// The unit constructor with lift() method
class unit
{
private $prototype;
private $modifier;
public function __construct($modifier)
{
$this->modifier = $modifier;
$this->prototype = new prototype();
}
protected function create($value)
{
$monad = new monad($this->prototype);
$monad->bind = function($func, $arguments = array()) use ($value) {
array_unshift($arguments, $value);
return call_user_func_array($func, $arguments);
};
if ($this->modifier) {
$modifier = $this->modifier;
$value = $modifier($monad, $value);
}
return $monad;
}
public function __invoke($value)
{
return $this->create($value);
}
public function lift($name, callable $func)
{
$unit = $this;
$this->prototype->$name = function() use ($func, $unit) {
$result = $this->bind($func, func_get_args());
return $result instanceof monad ? $result : $unit->create($result);
};
return $this;
}
public function lift_value($name, $func)
{
$this->prototype->$name = function() use ($func) {
return $this->bind($func, func_get_args());
};
return $this;
}
}
function MONAD(callable $modifier = null)
{
return new unit($modifier);
}
// LET'S PLAY
function alert($value)
{
echo "ALERT $value\n";
}
$identity = MONAD();
$monad = $identity('Hello world.');
$monad->bind('alert');
$ajax = MONAD()
->lift('alert', 'alert');
$monad = $ajax('Hello ajax.');
$monad->alert();
$maybe = MONAD(function($monad, $value) {
if (is_null($value)) {
$monad->bind = function() use ($monad) {
return $monad;
};
}
return $value;
});
$number = MONAD()
->lift('inc', function($value) {
return $value + 1;
});
$x = $number(100);
$x->inc()->inc()->bind('alert'); // 102
$monad = $maybe(null);
$monad->bind('alert'); // nothing
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment