Lead Developer, radify.io
warren@radify.io
@woogoose
function iAmPure($a, $b, $c) {
/* ... */
return $x;
}Don't try to do anything practical...
A monad is just a monoid in the category of endofunctors, what's the problem?
(>>=) :: (Monad m) => m a -> (a -> m b) -> m b
"Go learn Haskell"
"Go learn Category Theory"
(M t) → (t → Mu) → (M u)
"Monads are cursed...
Once you fully understand and appreciate Monads...
You lose the ability to explain them to other people."
Douglas Crockford
function unit($value) function bind($monad, function($value) { ... })
1. bind(unit($value), $fn) === $fn($value);
2. bind($monad, unit) === $monad;
3. bind(bind($monad, $fnA), $fnB) === bind($monad, function($value) { return bind($fnA($value), $fnB); });
$monad = Monad::unit($value)
$monad->bind($fn)
1. Monad::unit($value)->bind($fn) === $fn($value);
2. $monad->bind(Monad::unit) === $monad;
3. $monad->bind($fnA)->bind($fnB) === $monad->bind(function($value) { return $fnA($value)->bind($fnB); });
class Monad {
protected $_value;
public function __construct($value) {
$this->_value = $value;
}
public static function unit($value) {
return new static($value);
}
public function bind($fn) {
$result = $fn($this->_value);
return static::unit($result);
}
}'Wrap' our value
Constructor sugar
Satisfy Axioms 1 and 3
/* ... */
public static function unit($value) {
if ($value instanceof self) {
return $value;
}
return new static($value);
}
public function value() {
return $this->_value;
}
/* ... */Back to reality...
Satisfy Axiom 2
// Promises
$http.get('/api/products')
.then(function(products) {
return _.pluck(products, 'name');
})
.then(function(names) {
$scope.names = names;
});// jQuery
$('div.foo')
.css('background', 'red')
.css('color', 'white')
.html('hello world!');// Lodash/Underscore:
_(value)
.filter({category: 'book'})
.sortBy('price')
.reverse()
.value();// Doctrine QueryBuilder
$qb->select('u')
->from('User', 'u')
->where('u.id = ?1')
->orderBy('u.name', 'ASC')
->setParameter(1, 100);if ($x === null)
return;
public function grandParentName() {
return $this
->parent()
->parent()
->name;
}public function grandParentName() {
$parent = $this->parent();
if ($parent === null) {
return;
}
$grandParent = $parent->parent();
if ($grandParent === null) {
return;
}
return $grandParent->name;
}class Maybe extends Monad {
public function bind($fn) {
if ($this->_value === null) {
return $this;
}
return parent::bind($fn);
}
}The last null check you'll ever write
... maybe
/* ... */
public function call($name) {
return $this->bind(function($value) use ($name) {
return $value->name();
});
}
public function prop($name) {
return $this->bind(function($value) use ($name) {
return $value->prop;
});
}
/* ... */Method caller
Property getter