Skip to content

Instantly share code, notes, and snippets.

@pwm
Last active November 25, 2016 20:48
Show Gist options
  • Save pwm/2eb1fa03fcd54d8d32c21546ba80aa16 to your computer and use it in GitHub Desktop.
Save pwm/2eb1fa03fcd54d8d32c21546ba80aa16 to your computer and use it in GitHub Desktop.
My little explanation of what a functor is
<?php
// This would be a type class in Haskell.
// Any type that implements this interface/type class is a Functor.
interface Functor {
// map() takes a function and returns a Functor.
// The "Functor F" before the "=>" simply means that F implements Functor.
// map :: Functor F => (a -> b) -> F b
public function map(callable $fn);
}
// fmap() is a generic higher-order function that maps functions over Functors.
// it takes a function and a functor and returns a functor
// fmap :: Functor F => (a -> b) -> F a -> F b
function fmap(callable $fn, Functor $F) { return $F->map($fn); }
// The Maybe type is a Functor because it implements map().
class Just {
public $value;
public function __construct($value) { $this->value = $value; }
}
class Nothing {}
class Maybe implements Functor {
// This is the "a" from "F a", aka. the value inside the Functor.
private $value;
// This is just a generic way to put a value inside the Functor.
public static function unit($value) {
return new self($value);
}
// This is the reason why Maybe is a functor. It is always the implementation
// of the Functor that decides how to map a function over its content. In the case
// of Maybe it only applies the function to its value if the value is a Just.
public function map(callable $fn) {
return $this->value instanceof Just
? new Maybe($fn($this->value->value))
: new Maybe(new Nothing());
}
// As said above, in the case of Maybe, depending on whether the supplied value is
// something other than null or not it is stored as a Just or a Nothing.
private function __construct($value) {
$this->value = $value !== null && ! $value instanceof Nothing
? new Just($value)
: new Nothing();
}
}
// $add1 is just a normal everyday function, completely oblivious of Fairies, Dragons, Functors and whatnot.
$add1 = function ($x) { return $x + 1; };
// a Functor with Just(1) inside.
$maybeOne = Maybe::unit(1);
// When we map $add1 over Maybe(Just(1)) $add1 will be applied
// to the value inside and we'll get Maybe(Just(2)).
var_dump(fmap($add1, $maybeOne)); // = Maybe(Just(2))
// a Functor with Nothing inside.
$maybeNothing = Maybe::unit(null);
// When we map $add1 over Maybe(Nothing()) $add1 won't be applied
// to the value inside and we'll get Maybe(Nothing())
var_dump(fmap($add1, $maybeNothing)); // = Maybe(Nothing)
// List is another example of a Functor because map() is defined on it. In php it's called array_map().
// In the case of List map() is implemented so that it applies functions to every element of List.
// In general a Functor is any type that can mapped over, be it Maybe, List, etc...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment