Upcoming SlideShare
×

7,851 views

Published on

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

Published in: Technology
4 Likes
Statistics
Notes
• Full Name
Comment goes here.

Are you sure you want to Yes No
• Be the first to comment

Views
Total views
7,851
On SlideShare
0
From Embeds
0
Number of Embeds
330
Actions
Shares
0
23
0
Likes
4
Embeds 0
No embeds

No notes for slide

1. 1. Monads in Perlhiratara <hira.tara@gmail.com>
2. 2. About med.hatena.ne.jp/hirataratwitter.com/hirataraworking as a Perl programmera fan of Mathematicsa reporter of this YAPC
4. 4. Actually, monads arenot anything special.
5. 5. Category theory helps your understanding.
6. 6. An arrow is a function split Regex, Str, Int [Str] @str = split /\$regex/, \$str, \$n lengthStr Int\$len = length \$str
7. 7. Or represents a method newClassName CGI \$cgi = CGI->new param CGI, Str [Str] @values = \$cgi->param(\$str)
8. 8. Connecting two arrows * f g* *
9. 9. Connecting two arrows * f g f;g * * sub f;g {sub f;g { g(f(@_)) } or my @v = f(@_); g(@v) }
10. 10. The 2 laws of arrows
11. 11. 1) Identity sub id { @_ } f;idid f id id;f
12. 12. 2) Associativity f;(g;h)f g h (f;g);h
13. 13. Monad consists of Kleisli arrows
14. 14. Call a diagonal arrow a Kleisli arrowM(*) M(*) f * *
15. 15. Composition of 2 Kleisli arrowsM(*) M(*) M(*) f g * * *
16. 16. Composition of 2 Kleisli arrows sub f>=>g { f(@_)->ﬂat_map(&g) }M(*) M(*) M(*) f>=>g * * *
17. 17. The 2 laws of Kleisli arrows(i.e. Monad laws)
18. 18. 1) Identity sub unit { ... } M(*) f>=>unit * M(*) M(*) M(*) unit f unit* * * M(*) unit>=>f*
19. 19. 2) Associativity f>=>(g>=>h) M(*)* M(*) M(*)* * M(*) M(*) M(*) f g h* * * M(*) M(*)* (f>=>g)>=>h * M(*)
20. 20. Consider >=> as “a programmable ;“
22. 22. 1. Nested types MM(M(*)) M(M(*)) M(M(*)) M(M(*)) M(M(*))M(*) M(*) M(*) M(*) M(*) * * * * *
23. 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. 24. 3. The operation to lift up arrowsM(M(*)) M(M(*)) M(M(*)) M(M(*)) M(M(*)) ﬂat_map ﬂat_map ﬂat_map ﬂat_mapM(*) M(*) M(*) M(*) M(*) ﬂat_map ﬂat_map ﬂat_map ﬂat_map * * * * *
25. 25. POINT: M extends valuesM(*) \$m5 \$m3 \$m1 \$m2 \$m4 * 1 “foo” undef \$obj
26. 26. POINT: M extends valuesM(*) \$m5 \$m3 \$m1 \$m2 \$m4 unit(1) unit(“foo”) unit(undef) unit(\$obj) unit * 1 “foo” undef \$obj
27. 27. ex). List[*] [] [\$obj1, \$obj2, \$obj3] [1, 2, 3] [“foo”, “bar”] [undef, undef] [1] [“foo”] [undef] [\$obj]* 1 “foo” undef \$obj
28. 28. Monads provideextended values and its computations
29. 29. Let’s implement the List Monad
30. 30. All you have to do isdeﬁne a type and unit and ﬂat_map.
31. 31. Implementation of List Monad sub unit { [\$_[0]] } sub ﬂat_map { my (\$m, \$f) = @_; [map { @{\$f->(\$_)} } @\$m]; }
32. 32. Thats all we need!
33. 33. Well, are you interested in monads law?The check is left as an exercise :p
34. 34. Simple usage of List monads [3, 5] [\$n + 1, ..., \$n + 6] roll_dice \$nsub roll_dice { [map { \$_[0] + \$_ } 1 .. 6] }
35. 35. Simple usage of List monads roll_dice’ [4, 5, ..., 9, [3, 5] 6, 7, ..., 11] ﬂat_mapsub roll_dice’ { ﬂat_map \$_[0] => &roll_dice }
36. 36. When we deﬁne a monad, it comes with 2 relative functions.
37. 37. 1. map map(go_to_jail)[3, 5] [0, 0] map go_to_jail \$n 0
38. 38. 1. map map(go_to_jail) [3, 5] [0, 0]sub map_ { my (\$m, \$f) = @_; map ﬂat_map \$m => sub { unit(\$f->(\$_[0])) };} go_to_jail \$n 0
39. 39. 2. ﬂattenM(M(M(*))) M(M(M(*))) M(M(M(*))) M(M(M(*))) M(M(M(*))) ﬂatten ﬂatten ﬂatten ﬂatten ﬂattM(M(*)) M(M(*)) M(M(*)) M(M(*)) M(M(*)) ﬂatten ﬂatten ﬂatten ﬂatten ﬂatt M(*) M(*) M(*) M(*) M(*) * * * * *
40. 40. Implementation of ﬂatten ﬂattenM(M(*)) M(*) ﬂat_map id M(*) *
41. 41. Implementation of ﬂatten ﬂattensub ﬂatten { M(M(*)) M(*) my \$m = shift; ﬂat_map \$m => &id; ﬂat_map} id M(*) *
42. 42. ﬂatten() has animportant role on monads.
43. 43. Reduction of terms 6 3 2 8 + 9 2 8 + 11 8 + 19
44. 44. ﬂatten() plays the same role M (M (M (M (*)))) ﬂatten M (M (M (*))) ﬂatten M (M (*)) ﬂatten M (*)
45. 45. Can you illustrateanother example of monads?
46. 46. AnyEvent
47. 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. 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. 49. \$cv representsa future value.
50. 50. CondVar isn’t a normal value# !! Can’t write in this way !!sub some_callback { my \$cv = shift; print \$cv, “n”;}
51. 51. Retrieve the value from \$cv sub some_callback { my \$cv = shift; print \$cv->recv, “n”; }
52. 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. 53. You must use cb(). sub some_callback { my \$cv = shift; \$cv->cb(sub { print \$_[0]->recv, "n"; }); }
54. 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. 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. 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. 57. A callback-hell
58. 58. Coro solves the problem
59. 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. 60. Looks perfect!
61. 61. Though, Coro does some deep magic
62. 62. Organize the chaos by the monad pattern
63. 63. Let’s deﬁne a type andunit and ﬂat_map
64. 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. 65. Which CondVar objs do normal values correspond to?
66. 66. We can retrieve a normal value without delay sub unit { my @values = @_ my \$cv = AE::cv; \$cv->send(@values); return \$cv; }
67. 67. Think about ﬂat_map() “foo” “Hi, \$_[0]”after 3 sec after 2 sec ﬂat_map say_hi \$_[0] *
68. 68. Think about ﬂat_map()\$name->ﬂat_map(&say_hi) 5 sec “Hi, foo”say_hi 2 sec “Hi, foo”\$name 3 sec “foo”
69. 69. Implementation of ﬂat_mapsub ﬂat_map { my (\$cv, \$f) = @_; \$cv->cb(sub { my @values = \$_[0]->recv; my \$cv = \$f->(@values); ... }) return ...}
70. 70. Implementation of ﬂat_mapsub ﬂat_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. 71. A monad comes with map and ﬂatten
74. 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. 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. 76. Handle exceptions in ﬂat_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. 77. Deﬁne subs to handle errors sub fail { my @values = @_ my \$cv = AE::cv; \$cv->croak(@values); return \$cv; }
78. 78. Deﬁne 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. 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. 80. Does everything go well?
81. 81. NO
82. 82. ConcurrencyCV(*), CV(*) CV(*, *)
83. 83. Concurrency sequenceCV(*), CV(*) CV(*, *)
84. 84. There’re no alchemy. OoCV(*, *) ps! CV(*, *) map id *, * *, *
85. 85. Deﬁne it directlysub sequence { my (\$cv1, \$cv2) = @_; \$cv1->ﬂat_map(sub { my @v1 = @_; \$cv2->ﬂat_map(sub { my @v2 = @_; unit(@v1, @v2); }); });}
86. 86. Use nested blocks to handle more than one monad \$cv1->ﬂat_map(sub { my @v1 = @_; \$cv2->ﬂat_map(sub { my @v2 = @_; \$cv3->ﬂat_map(sub { my @v3 = @_; \$cv4->ﬂat_map(sub { my @v4 = @_; \$cv5->ﬂat_map(sub { my @v5 = @_; ...
87. 87. Back to the hell
88. 88. Haskell’s do expressiondo v1 <- cv1 v2 <- cv2 v3 <- cv3 v4 <- cv4 ... return (v1, v2, v3, v4, ...)
89. 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. 90. ex). Better implementation of sequence sub sequence { my (\$cv1, \$cv2) = @_; \$cv1->ﬂat_map(sub { my @v1 = @_; \$cv2->ﬂat_map(sub { my @v2 = @_; unit(@v1, @v2); }); }); }
91. 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 }; }; }