Your SlideShare is downloading. ×
Monads in perl
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Introducing the official SlideShare app

Stunning, full-screen experience for iPhone and Android

Text the download link to your phone

Standard text messaging rates apply

Monads in perl

3,401
views

Published on

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.

Published in: Technology

0 Comments
4 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
3,401
On Slideshare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
Downloads
21
Comments
0
Likes
4
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

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