Monads in perl
Upcoming SlideShare
Loading in...5
×
 

Like this? Share it with your network

Share

Monads in perl

on

  • 3,756 views

The slide shows what monads are and how I implement it in Perl.

The slide shows what monads are and how I implement it in Perl.

Statistics

Views

Total Views
3,756
Views on SlideShare
3,471
Embed Views
285

Actions

Likes
4
Downloads
15
Comments
0

8 Embeds 285

http://yapcasia.org 260
https://twitter.com 12
http://paper.li 8
http://a0.twimg.com 1
http://webcache.googleusercontent.com 1
https://si0.twimg.com 1
https://web.tweetdeck.com 1
http://www.slashdocs.com 1
More...

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Monads in perl Presentation Transcript

  • 1. Monads in Perlhiratara <hira.tara@gmail.com>
  • 2. About med.hatena.ne.jp/hirataratwitter.com/hirataraworking as a Perl programmera fan of Mathematicsa reporter of this YAPC
  • 3. What are Monads?
  • 4. Actually, monads arenot anything special.
  • 5. Category theory helps your understanding.
  • 6. An arrow is a function split Regex, Str, Int [Str] @str = split /$regex/, $str, $n lengthStr Int$len = length $str
  • 7. Or represents a method newClassName CGI $cgi = CGI->new param CGI, Str [Str] @values = $cgi->param($str)
  • 8. Connecting two arrows * f g* *
  • 9. Connecting two arrows * f g f;g * * sub f;g {sub f;g { g(f(@_)) } or my @v = f(@_); g(@v) }
  • 10. The 2 laws of arrows
  • 11. 1) Identity sub id { @_ } f;idid f id id;f
  • 12. 2) Associativity f;(g;h)f g h (f;g);h
  • 13. Monad consists of Kleisli arrows
  • 14. Call a diagonal arrow a Kleisli arrowM(*) M(*) f * *
  • 15. Composition of 2 Kleisli arrowsM(*) M(*) M(*) f g * * *
  • 16. Composition of 2 Kleisli arrows sub f>=>g { f(@_)->flat_map(&g) }M(*) M(*) M(*) f>=>g * * *
  • 17. The 2 laws of Kleisli arrows(i.e. Monad laws)
  • 18. 1) Identity sub unit { ... } M(*) f>=>unit * M(*) M(*) M(*) unit f unit* * * M(*) unit>=>f*
  • 19. 2) Associativity f>=>(g>=>h) M(*)* M(*) M(*)* * M(*) M(*) M(*) f g h* * * M(*) M(*)* (f>=>g)>=>h * M(*)
  • 20. Consider >=> as “a programmable ;“
  • 21. Monads are made of 3 things
  • 22. 1. Nested types MM(M(*)) M(M(*)) M(M(*)) M(M(*)) M(M(*))M(*) M(*) M(*) M(*) M(*) * * * * *
  • 23. 2. A set of arrows to wrap valuesM(M(*)) M(M(*)) M(M(*)) M(M(*)) M(M(*)) unit unit unit unitM(*) M(*) M(*) M(*) M(*) unit unit unit unit * * * * *
  • 24. 3. The operation to lift up arrowsM(M(*)) M(M(*)) M(M(*)) M(M(*)) M(M(*)) flat_map flat_map flat_map flat_mapM(*) M(*) M(*) M(*) M(*) flat_map flat_map flat_map flat_map * * * * *
  • 25. POINT: M extends valuesM(*) $m5 $m3 $m1 $m2 $m4 * 1 “foo” undef $obj
  • 26. POINT: M extends valuesM(*) $m5 $m3 $m1 $m2 $m4 unit(1) unit(“foo”) unit(undef) unit($obj) unit * 1 “foo” undef $obj
  • 27. ex). List[*] [] [$obj1, $obj2, $obj3] [1, 2, 3] [“foo”, “bar”] [undef, undef] [1] [“foo”] [undef] [$obj]* 1 “foo” undef $obj
  • 28. Monads provideextended values and its computations
  • 29. Let’s implement the List Monad
  • 30. All you have to do isdefine a type and unit and flat_map.
  • 31. Implementation of List Monad sub unit { [$_[0]] } sub flat_map { my ($m, $f) = @_; [map { @{$f->($_)} } @$m]; }
  • 32. Thats all we need!
  • 33. Well, are you interested in monads law?The check is left as an exercise :p
  • 34. Simple usage of List monads [3, 5] [$n + 1, ..., $n + 6] roll_dice $nsub roll_dice { [map { $_[0] + $_ } 1 .. 6] }
  • 35. Simple usage of List monads roll_dice’ [4, 5, ..., 9, [3, 5] 6, 7, ..., 11] flat_mapsub roll_dice’ { flat_map $_[0] => &roll_dice }
  • 36. When we define a monad, it comes with 2 relative functions.
  • 37. 1. map map(go_to_jail)[3, 5] [0, 0] map go_to_jail $n 0
  • 38. 1. map map(go_to_jail) [3, 5] [0, 0]sub map_ { my ($m, $f) = @_; map flat_map $m => sub { unit($f->($_[0])) };} go_to_jail $n 0
  • 39. 2. flattenM(M(M(*))) M(M(M(*))) M(M(M(*))) M(M(M(*))) M(M(M(*))) flatten flatten flatten flatten flattM(M(*)) M(M(*)) M(M(*)) M(M(*)) M(M(*)) flatten flatten flatten flatten flatt M(*) M(*) M(*) M(*) M(*) * * * * *
  • 40. Implementation of flatten flattenM(M(*)) M(*) flat_map id M(*) *
  • 41. Implementation of flatten flattensub flatten { M(M(*)) M(*) my $m = shift; flat_map $m => &id; flat_map} id M(*) *
  • 42. flatten() has animportant role on monads.
  • 43. Reduction of terms 6 3 2 8 + 9 2 8 + 11 8 + 19
  • 44. flatten() plays the same role M (M (M (M (*)))) flatten M (M (M (*))) flatten M (M (*)) flatten M (*)
  • 45. Can you illustrateanother example of monads?
  • 46. AnyEvent
  • 47. Sample code of AEmy $cv = AE::cv;http_get "http://yapcasia.org/2011/", sub { my ($data, $hdr) = @_; $cv->send($hdr->{content-length});};print $cv->recv;
  • 48. Sample code of AEmy $cv = AE::cv;http_get "http://yapcasia.org/2011/", sub { my ($data, $hdr) = @_; $cv->send($hdr->{content-length});};print $cv->recv;
  • 49. $cv representsa future value.
  • 50. CondVar isn’t a normal value# !! Can’t write in this way !!sub some_callback { my $cv = shift; print $cv, “n”;}
  • 51. Retrieve the value from $cv sub some_callback { my $cv = shift; print $cv->recv, “n”; }
  • 52. Run it !% perl ./my_great_app.plEV: error in callback (ignoring):AnyEvent::CondVar: recursive blocking waitattempted at ./my_great_app.pl line 9836
  • 53. You must use cb(). sub some_callback { my $cv = shift; $cv->cb(sub { print $_[0]->recv, "n"; }); }
  • 54. Use cb()sub some_callback { my $cv = shift; $cv->cb(sub { my $cv = next_task1 $_[0]->recv; $cv->cb(sub { my $cv = next_task2 $_[0]->recv; ... }); });}
  • 55. Use cb()sub some_callback { my $cv = shift; $cv->cb(sub { my $cv = next_task1 $_[0]->recv; $cv->cb(sub { my $cv = next_task2 $_[0]->recv; $cv->cb(sub { my $cv = next_task3 $_[0]->recv; $cv->cb(sub { my $cv = next_task4 $_[0]->recv; ... }); }); }); });}
  • 56. $cv->cb(sub { my $cv = next_task2 $_[0]->recv; $cv->cb(sub { Use cb() my $cv = next_task3 $_[0]->recv; $cv->cb(sub { my $cv = next_task4 $_[0]->recv; $cv->cb(sub { my $cv = next_task5 $_[0]->recv; $cv->cb(sub { my $cv = next_task6 $_[0]->recv; $cv->cb(sub { my $cv = next_task7 $_[0]->recv; $cv->cb(sub { my $cv = next_task8 $_[0]->recv; $cv->cb(sub { my $cv = next_task9 $_[0]->recv; $cv->cb(sub { my $cv = next_task10 $_[0]->recv; ... }); }); }); }); }); });
  • 57. A callback-hell
  • 58. Coro solves the problem
  • 59. Use Coro::AnyEventsub some_callback { my $cv = shift; async { my $cv1 = next_task1($cv->recv); my $cv2 = next_task2($cv1->recv); my $cv3 = next_task3($cv2->recv); my $cv4 = next_task4($cv3->recv); ... };}
  • 60. Looks perfect!
  • 61. Though, Coro does some deep magic
  • 62. Organize the chaos by the monad pattern
  • 63. Let’s define a type andunit and flat_map
  • 64. AE::CondVar is the type# CondVar(STR)my $cv = AE::cv;$cv->send(‘Normal value’);# CondVar(CondVar(Str))my $cvcv = AE::cv;$cvcv->send($cv);# CondVar(CondVar(CondVar(Str)))my $cvcvcv = AE::cv;$cvcvcv->send($cvcv);
  • 65. Which CondVar objs do normal values correspond to?
  • 66. We can retrieve a normal value without delay sub unit { my @values = @_ my $cv = AE::cv; $cv->send(@values); return $cv; }
  • 67. Think about flat_map() “foo” “Hi, $_[0]”after 3 sec after 2 sec flat_map say_hi $_[0] *
  • 68. Think about flat_map()$name->flat_map(&say_hi) 5 sec “Hi, foo”say_hi 2 sec “Hi, foo”$name 3 sec “foo”
  • 69. Implementation of flat_mapsub flat_map { my ($cv, $f) = @_; $cv->cb(sub { my @values = $_[0]->recv; my $cv = $f->(@values); ... }) return ...}
  • 70. Implementation of flat_mapsub flat_map { my ($cv, $f) = @_; my $result = AE::cv; $cv->cb(sub { my @values = $_[0]->recv; my $cv = $f->(@values); $cv->cb(sub { $result->send($_[0]->recv) }); }); return $result;}
  • 71. A monad comes with map and flatten
  • 72. Use the CondVar monad$cv ∋CV(*) CV(*) CV(*)flat_map flat_map next_task1 next_task2 * * *
  • 73. Use the CondVar monad$cv sub some_callback { ∋ my $cv = shift;CV(*) CV(*) CV(*) $cv->flat_map(&next_task1)flat_map flat_map ->flat_map(&next_task2) ->flat_map(&next_task3) ->flat_map(&next_task4) ->... } next_task1 next_task2 * * *
  • 74. The CV monad has thecontinuation monad structure newtype Cont r a = Cont { runCont :: (a -> r) -> r } runCont cv $ v -> print v $cv->cb(sub { my @v = $_[0]->recv; print @v; });
  • 75. The CV monad also has the Either monad structuredata Either String a = Left String | Right a(my $right = AE::cv)->send(“A right value”);(my $left = AE::cv)->croak(“A left value”);
  • 76. Handle exceptions in flat_mapLeft l >>= _ = Left lRight r >>= f = f r...my $result = AE::cv;$cv->cb(sub { my @r = eval { $_[0]->recv }; return $result->croak($@) if $@; my $cv = $f->(@r); ...});...
  • 77. Define subs to handle errors sub fail { my @values = @_ my $cv = AE::cv; $cv->croak(@values); return $cv; }
  • 78. Define subs to handle errors sub catch { ... my $result = AE::cv; $cv->cb(sub { my @r = eval { $_[0]->recv }; return $result->send(@r) if @r; my $cv = $f->($@); ... }); ...
  • 79. A sample code of catchunit(1, 0)->flat_map(sub { my @v = eval { $_[0] / $_[1] }; $@ ? fail($@) : unit(@v);})->catch(sub { my $exception = shift; $exception =~ /Illegal division/ ? unit(0) # recover from errors : fail($exception); # rethrow})->flat_map(sub { ...});
  • 80. Does everything go well?
  • 81. NO
  • 82. ConcurrencyCV(*), CV(*) CV(*, *)
  • 83. Concurrency sequenceCV(*), CV(*) CV(*, *)
  • 84. There’re no alchemy. OoCV(*, *) ps! CV(*, *) map id *, * *, *
  • 85. Define it directlysub sequence { my ($cv1, $cv2) = @_; $cv1->flat_map(sub { my @v1 = @_; $cv2->flat_map(sub { my @v2 = @_; unit(@v1, @v2); }); });}
  • 86. Use nested blocks to handle more than one monad $cv1->flat_map(sub { my @v1 = @_; $cv2->flat_map(sub { my @v2 = @_; $cv3->flat_map(sub { my @v3 = @_; $cv4->flat_map(sub { my @v4 = @_; $cv5->flat_map(sub { my @v5 = @_; ...
  • 87. Back to the hell
  • 88. Haskell’s do expressiondo v1 <- cv1 v2 <- cv2 v3 <- cv3 v4 <- cv4 ... return (v1, v2, v3, v4, ...)
  • 89. The for comprehensionData::Monad::Base::Sugar::for { pick my @v1 => sub { $cv1 }; pick my @v2 => sub { $cv2 }; pick my @v3 => sub { $cv3 }; pick my @v4 => sub { $cv4 }; ... yield { @v1, @v2, @v3, @v4, ... };};
  • 90. ex). Better implementation of sequence sub sequence { my ($cv1, $cv2) = @_; $cv1->flat_map(sub { my @v1 = @_; $cv2->flat_map(sub { my @v2 = @_; unit(@v1, @v2); }); }); }
  • 91. ex). Better implementation of sequence sub sequence { my ($cv1, $cv2) = @_; Data::Monad::Base::Sugar::for { pick my @v1 => sub { $cv1 }; pick my @v2 => sub { $cv2 }; yield { @v1, @v2 }; }; }
  • 92. Conclusion A monad is made of a type, flat_map, unit Consider AE::cv as a monad CondVar monads save you from a callback hellhttps://github.com/hiratara/p5-Data-Monad