Maybes and Functors

Maybes and Functors

A brief introductions to functors and the Maybe type, briefly touching on a tiny bit of Monadic properties

8f9f6a577da77a9add9cadbb90e66b75?s=128

Matthew Machuga

July 26, 2017
Tweet

Transcript

  1. 3.
  2. 8.

    Contrived Ex 1: $users = collect([ new User([“id” => 1,

    “name” => “Rommie Bot”]), new User([“id” => 2, “name” => “Liona Bot”]) ]); $getInfo = function($user) { return $user->name; }; $toSlug = function($name) { return strtolower(str_replace(“ “, “-“, $name)); }; $slugifiedNames = $collection->map($getInfo)->map($toSlug); $slugifiedNames // => [“rommie-bot”, “liona-bot”]
  3. 11.

    Interesting Properties / Functor Laws // map won’t run if

    the collection is empty $c->map(function($x) { return $x; }) == $c 
 $c->map($getInfo)->map($toSlug) == $c->map(function($user) { return $toSlug($getInfo($user)); }); // map(f).map(g) == map(g o f)
  4. 16.

    Let's create a type • Follow the two rules •

    c.map(g).map(f) == c.map(g o f) • c.map(id) == c • Define a way to get to our raw value
  5. 18.

    Box <?php class Box { protected $value; public static function

    of($value) { return new static($value); } public function __construct($value) { $this->value = $value; } public function map(callable $f) : Box { return new static($f($this->value)); } public function fold(callable $f = null) { return $f ? $f($this->value) : $this->value; } }
  6. 19.

    Collection Example $users = collect([ new User([“id” => 1, “name”

    => “Rommie Bot”]), new User([“id” => 2, “name” => “Liona Bot”]) ]); $getInfo = function($user) { return $user->name; }; $toSlug = function($name) { return strtolower(str_replace(“ “, “-“, $name)); }; $slugifiedNames = $collection->map($getInfo)->map($toSlug); $slugifiedNames // => [“rommie-bot”, “liona-bot”]
  7. 20.

    Box Example $box = Box::of(new User([“id” => 1, “name” =>

    “Liona Bot”])); $getInfo = function($user) { return $user->name; }; $toSlug = function($name) { return strtolower(str_replace(“ “, “-“, $name)); }; $slugifiedNameInBox = $box->map($getInfo)->map($toSlug); $slugifiedNameInBox // => Box(“liona-bot”) $slugifiedNameInBox->fold() // => “liona-bot”
  8. 24.
  9. 25.
  10. 26.
  11. 27.
  12. 28.

    You start getting this $value = collect([somethingThatMightBeNull()]) ->map(function($v) { if

    ($v && method_exists($v, ‘byebye’)) { return $v->byebye(); } });
  13. 29.
  14. 30.

    Or possibly this.. $value = collect([somethingThatMightBeNull()]) ->filter(function($el) { return !!$el;

    }) ->map(function($v) { return $v->byebye(); }); // map(f).map(g) == map(g o f)
  15. 32.
  16. 33.
  17. 35.

    What does null mean? 1. The element was not found

    2. The element was found and is null
  18. 39.
  19. 42.

    Contrived Ex 1 Reprise: $collection = collect([ Maybe::just(1), Maybe::nothing() ]);

    $value = $collection->find(function($el) { return $el->fold() === 42; }); $value // => Nothing
  20. 43.

    Contrived Ex 1 Reprise: $collection = collect([ Maybe::just(1), Maybe::nothing() ]);

    $value = $collection->find(function($el) { return $el->fold() === null; }); $value // => Just(null)
  21. 44.

    Contrived Ex 1 Reprise: $collection = collect([ Maybe::just(1), Maybe::nothing() ]);

    $value = $collection->find(function($el) { return $el->fold() === 1; }); $value // => Just(1)
  22. 46.
  23. 48.

    A better way... $maybeUser = Eloquent::maybeFind(9001); $something = $maybeUser->map(function($user) {

    return SomeObject::someTransformationLol($user); }); // Later in the app function process(Maybe $maybeData) { return $maybeData->fold(function($value) { // If you need to do a side-effect dependent on if null // Could finally check here }); }
  24. 49.
  25. 50.

    Nested Types $value = Box::of(1)->map(function($id) { return Eloquent::maybeFind(9001); }); //

    Box(Just(User)) | Box(Nothing) $value->map(function($user) { // $user is a Just(User) return $user->profile; }); // Box(Just(Maybe(User)))
  26. 54.
  27. 55.

    Nested Types $value = Box::of(1)->chain(function($id) { return Eloquent::maybeFind(9001); }); //

    Just(User) | Nothing $value->chain(function($user) { return $user->profile; }); // Maybe(Profile)
  28. 56.

    You don’t like closures? <?php class ConvertToTruth { public function

    convert($text) { return str_replace('the cloud', “someone else's computer", $text); } public function __invoke($text) { return $this->convert($text); } }
  29. 57.

    You don’t like closures? collect(["My data lives in the cloud"])

    ->map(new ConvertToTruth) ->toArray() // [“My data lives in someone else’s machine”] // or Box::of(“My data lives in the cloud") ->map(new ConvertToTruth) ->fold() // My data lives in someone else’s machine
  30. 62.

    Resources • Professor Frisby’s Mostly Adequate Guide to Functional Programming

    - Brian Lonsdorf (@drboolean) • https://drboolean.gitbooks.io/mostly-adequate-guide/content/ • https://egghead.io/courses/professor-frisby-introduces-composable- functional-javascript • Elm • http://elm-lang.org • Maybe Haskell - Pat Brisbin: • https://gumroad.com/l/maybe-haskell/