Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Maybes and Functors

Maybes and Functors

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

Matt Machuga

July 26, 2017
Tweet

More Decks by Matt Machuga

Other Decks in Programming

Transcript

  1. 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”]
  2. 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)
  3. 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
  4. 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; } }
  5. 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”]
  6. 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”
  7. You start getting this $value = collect([somethingThatMightBeNull()]) ->map(function($v) { if

    ($v && method_exists($v, ‘byebye’)) { return $v->byebye(); } });
  8. 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)
  9. What does null mean? 1. The element was not found

    2. The element was found and is null
  10. Contrived Ex 1 Reprise: $collection = collect([ Maybe::just(1), Maybe::nothing() ]);

    $value = $collection->find(function($el) { return $el->fold() === 42; }); $value // => Nothing
  11. Contrived Ex 1 Reprise: $collection = collect([ Maybe::just(1), Maybe::nothing() ]);

    $value = $collection->find(function($el) { return $el->fold() === null; }); $value // => Just(null)
  12. Contrived Ex 1 Reprise: $collection = collect([ Maybe::just(1), Maybe::nothing() ]);

    $value = $collection->find(function($el) { return $el->fold() === 1; }); $value // => Just(1)
  13. 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 }); }
  14. 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)))
  15. 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)
  16. 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); } }
  17. 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
  18. 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/