Your SlideShare is downloading. ×
0
Monads in Perlhiratara <hira.tara@gmail.com>
About med.hatena.ne.jp/hirataratwitter.com/hirataraworking as a Perl programmera fan of Mathematicsa reporter of this YAPC
What are Monads?
Actually, monads arenot anything special.
Category theory helps your understanding.
An arrow is a function                                   split               Regex, Str, Int                [Str]         ...
Or represents a method            newClassName              CGI     $cgi = CGI->new                             param     ...
Connecting two arrows          *     f         g*                  *
Connecting two arrows                        *             f                   g                       f;g     *          ...
The 2 laws of arrows
1) Identity      sub id { @_ }                f;idid          f          id     id;f
2) Associativity        f;(g;h)f           g          h        (f;g);h
Monad consists of Kleisli arrows
Call a diagonal arrow    a Kleisli arrowM(*)            M(*)        f *                *
Composition of             2 Kleisli arrowsM(*)         M(*)        M(*)       f            g *            *            *
Composition of             2 Kleisli arrows       sub f>=>g { f(@_)->flat_map(&g) }M(*)                M(*)                ...
The 2 laws of          Kleisli arrows(i.e. Monad laws)
1) Identity               sub unit { ... }                                            M(*)                          f>=>un...
2) Associativity         f>=>(g>=>h)               M(*)*                                  M(*)          M(*)*         *   ...
Consider >=> as   “a programmable ;“
Monads are made of             3 things
1. Nested types MM(M(*))   M(M(*))   M(M(*))   M(M(*))   M(M(*))M(*)       M(*)       M(*)     M(*)       M(*)  *         ...
2. A set of arrows                 to wrap valuesM(M(*))      M(M(*))        M(M(*))         M(M(*))        M(M(*))      u...
3. The operation            to lift up arrowsM(M(*))   M(M(*))   M(M(*))    M(M(*))    M(M(*))  flat_map     flat_map     fla...
POINT: M extends valuesM(*)                         $m5            $m3           $m1                  $m2             $m4 ...
POINT: M extends valuesM(*)                           $m5                      $m3           $m1                    $m2   ...
ex). List[*]                           []   [$obj1, $obj2, $obj3]       [1, 2, 3]              [“foo”, “bar”] [undef, unde...
Monads provideextended values and  its computations
Let’s implement         the List Monad
All you have to do isdefine a type and unit     and flat_map.
Implementation of List Monad     sub unit { [$_[0]] }     sub flat_map {        my ($m, $f) = @_;        [map { @{$f->($_)}...
Thats all we need!
Well, are you interested in                   monads law?The check is left as                 an exercise :p
Simple usage of List monads  [3, 5]                          [$n + 1, ..., $n + 6]                      roll_dice    $nsub...
Simple usage of List monads                       roll_dice’     [4, 5, ..., 9,    [3, 5]                                 ...
When we define a monad,     it comes with  2 relative functions.
1. map         map(go_to_jail)[3, 5]                     [0, 0]                map           go_to_jail $n                ...
1. map             map(go_to_jail) [3, 5]                           [0, 0]sub map_ {   my ($m, $f) = @_;                  ...
2. flattenM(M(M(*)))   M(M(M(*)))   M(M(M(*)))   M(M(M(*)))   M(M(M(*)))   flatten        flatten       flatten       flatten  ...
Implementation of      flatten              flattenM(M(*))                M(*)        flat_map                  id M(*)      ...
Implementation of           flatten                 flattensub flatten {     M(M(*))              M(*)   my $m = shift;   flat...
flatten() has animportant role on    monads.
Reduction of terms   6       3            2        8       +       9                2        8                    +       ...
flatten() plays the same role        M       (M     (M   (M (*))))            flatten            M          (M (M (*)))     ...
Can you illustrateanother example of     monads?
AnyEvent
Sample code of AEmy $cv = AE::cv;http_get "http://yapcasia.org/2011/", sub {   my ($data, $hdr) = @_;   $cv->send($hdr->{c...
Sample code of AEmy $cv = AE::cv;http_get "http://yapcasia.org/2011/", sub {   my ($data, $hdr) = @_;   $cv->send($hdr->{c...
$cv representsa future value.
CondVar isn’t     a normal value# !! Can’t write in this way !!sub some_callback {   my $cv = shift;    print $cv, “n”;}
Retrieve the value from $cv   sub some_callback {      my $cv = shift;       print $cv->recv, “n”;   }
Run it !% perl ./my_great_app.plEV: error in callback (ignoring):AnyEvent::CondVar: recursive blocking waitattempted at ./...
You must use cb(). sub some_callback {    my $cv = shift;     $cv->cb(sub {         print $_[0]->recv, "n";     }); }
Use cb()sub some_callback {   my $cv = shift;    $cv->cb(sub {        my $cv = next_task1 $_[0]->recv;        $cv->cb(sub ...
Use cb()sub some_callback {   my $cv = shift;    $cv->cb(sub {        my $cv = next_task1 $_[0]->recv;        $cv->cb(sub ...
$cv->cb(sub {   my $cv = next_task2 $_[0]->recv;   $cv->cb(sub {              Use cb()      my $cv = next_task3 $_[0]->rec...
A callback-hell
Coro solves              the problem
Use Coro::AnyEventsub some_callback {   my $cv = shift;    async {       my $cv1 = next_task1($cv->recv);       my $cv2 = ...
Looks perfect!
Though, Coro does     some deep magic
Organize the chaos by the monad pattern
Let’s define a type andunit and flat_map
AE::CondVar is the type# CondVar(STR)my $cv = AE::cv;$cv->send(‘Normal value’);# CondVar(CondVar(Str))my $cvcv = AE::cv;$c...
Which CondVar objs do normal values  correspond to?
We can retrieve a normal  value without delay sub unit {    my @values = @_     my $cv = AE::cv;     $cv->send(@values);  ...
Think about flat_map()   “foo”                   “Hi, $_[0]”after 3 sec                after 2 sec        flat_map          ...
Think about flat_map()$name->flat_map(&say_hi)                    5 sec         “Hi, foo”say_hi                      2 sec “...
Implementation of         flat_mapsub flat_map {   my ($cv, $f) = @_;    $cv->cb(sub {       my @values = $_[0]->recv;      ...
Implementation of            flat_mapsub flat_map {   my ($cv, $f) = @_;    my $result = AE::cv;    $cv->cb(sub {        my ...
A monad comes with  map and flatten
Use the CondVar monad$cv ∋CV(*)                  CV(*)                CV(*)flat_map                flat_map          next_ta...
Use the CondVar monad$cv        sub some_callback { ∋           my $cv = shift;CV(*)                         CV(*)        ...
The CV monad has thecontinuation monad structure   newtype Cont r a = Cont {      runCont :: (a -> r) -> r   }   runCont c...
The CV monad also has the  Either monad structuredata Either String a = Left String | Right a(my $right = AE::cv)->send(“A...
Handle exceptions in     flat_mapLeft l >>= _ = Left lRight r >>= f = f r...my $result = AE::cv;$cv->cb(sub {    my @r = ev...
Define subs to handle errors  sub fail {     my @values = @_      my $cv = AE::cv;      $cv->croak(@values);      return $c...
Define subs to handle errors   sub catch {      ...      my $result = AE::cv;      $cv->cb(sub {          my @r = eval { $_...
A sample code of catchunit(1, 0)->flat_map(sub {    my @v = eval { $_[0] / $_[1] };    $@ ? fail($@) : unit(@v);})->catch(...
Does everything              go well?
NO
ConcurrencyCV(*), CV(*)            CV(*, *)
Concurrency               sequenceCV(*), CV(*)              CV(*, *)
There’re no alchemy.                 OoCV(*, *)              ps!   CV(*, *)           map                  id  *, *       ...
Define it directlysub sequence {   my ($cv1, $cv2) = @_;    $cv1->flat_map(sub {        my @v1 = @_;        $cv2->flat_map(su...
Use nested blocks to handle   more than one monad  $cv1->flat_map(sub {     my @v1 = @_;        $cv2->flat_map(sub {        ...
Back to the hell
Haskell’s do expressiondo v1   <-   cv1  v2    <-   cv2  v3    <-   cv3  v4    <-   cv4  ...  return (v1, v2, v3, v4, ...)
The for comprehensionData::Monad::Base::Sugar::for {   pick my @v1 => sub { $cv1 };   pick my @v2 => sub { $cv2 };   pick ...
ex). Better implementation of          sequence   sub sequence {      my ($cv1, $cv2) = @_;       $cv1->flat_map(sub {     ...
ex). Better implementation of          sequence   sub sequence {      my ($cv1, $cv2) = @_;       Data::Monad::Base::Sugar...
Conclusion   A monad is made of a type,   flat_map, unit   Consider AE::cv as a monad   CondVar monads save you from a   ca...
Upcoming SlideShare
Loading in...5
×

Monads in perl

3,994

Published on

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,994
On Slideshare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
Downloads
22
Comments
0
Likes
4
Embeds 0
No embeds

No notes for slide

Transcript of "Monads in perl"

  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
  3. 3. What are Monads?
  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(@_)->flat_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 ;“
  21. 21. Monads are made of 3 things
  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(*)) flat_map flat_map flat_map flat_mapM(*) M(*) M(*) M(*) M(*) flat_map flat_map flat_map flat_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 isdefine a type and unit and flat_map.
  31. 31. Implementation of List Monad sub unit { [$_[0]] } sub flat_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] flat_mapsub roll_dice’ { flat_map $_[0] => &roll_dice }
  36. 36. When we define 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 flat_map $m => sub { unit($f->($_[0])) };} go_to_jail $n 0
  39. 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. 40. Implementation of flatten flattenM(M(*)) M(*) flat_map id M(*) *
  41. 41. Implementation of flatten flattensub flatten { M(M(*)) M(*) my $m = shift; flat_map $m => &id; flat_map} id M(*) *
  42. 42. flatten() has animportant role on monads.
  43. 43. Reduction of terms 6 3 2 8 + 9 2 8 + 11 8 + 19
  44. 44. flatten() plays the same role M (M (M (M (*)))) flatten M (M (M (*))) flatten M (M (*)) flatten 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 define a type andunit and flat_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 flat_map() “foo” “Hi, $_[0]”after 3 sec after 2 sec flat_map say_hi $_[0] *
  68. 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. 69. Implementation of flat_mapsub flat_map { my ($cv, $f) = @_; $cv->cb(sub { my @values = $_[0]->recv; my $cv = $f->(@values); ... }) return ...}
  70. 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. 71. A monad comes with map and flatten
  72. 72. Use the CondVar monad$cv ∋CV(*) CV(*) CV(*)flat_map flat_map next_task1 next_task2 * * *
  73. 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. 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 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. 77. Define subs to handle errors sub fail { my @values = @_ my $cv = AE::cv; $cv->croak(@values); return $cv; }
  78. 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. 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. Define it directlysub sequence { my ($cv1, $cv2) = @_; $cv1->flat_map(sub { my @v1 = @_; $cv2->flat_map(sub { my @v2 = @_; unit(@v1, @v2); }); });}
  86. 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. 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->flat_map(sub { my @v1 = @_; $cv2->flat_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 }; }; }
  92. 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
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×