Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Functional Pe(a)rls version 2

2,601 views

Published on

Some techniques from the heady world of Functional Programming implemented in idiomatic Perl using various techniques: closures, iterators, Devel::Declare, and some distilled evil. New version now with monads! (As presented at http://conferences.yapceurope.org/lpw2008/ )

Published in: Technology
  • Be the first to comment

Functional Pe(a)rls version 2

  1. 1. Functional pe(a)rls <ul><ul><li>London Perl Workshop </li></ul></ul><ul><ul><li>29/11/2008 </li></ul></ul><ul><ul><li>version 2 </li></ul></ul><ul><ul><li>osfameron </li></ul></ul>
  2. 2. A sequence <ul><li>Debolaz, on #moose </li></ul><ul><li>a list of numbers like </li></ul><ul><ul><li>10, 25, 50, </li></ul></ul><ul><ul><li>100, 250, 500, </li></ul></ul><ul><ul><li>1000, etc </li></ul></ul><ul><li>without tracking any other state than the number itself </li></ul>
  3. 3. A sequence <ul><li>1. (power of 10) * 2.5 </li></ul><ul><li>2. * 2 </li></ul><ul><li>3. * 2 </li></ul>
  4. 4. A sequence <ul><ul><li>without tracking any other state than the number itself </li></ul></ul>
  5. 5. A sequence <ul><ul><li>/^1/ </li></ul></ul>
  6. 6. A sequence <ul><ul><li>/^1/ # power of 10 </li></ul></ul>
  7. 7. A sequence <ul><li>cycle [2.5, 2, 2] </li></ul>
  8. 8. A sequence <ul><li>cycle [2.5, 2, 2] </li></ul><ul><ul><li>2.5 </li></ul></ul><ul><ul><li>2 </li></ul></ul><ul><ul><li>2 </li></ul></ul><ul><ul><li>2.5 </li></ul></ul><ul><ul><li>... </li></ul></ul>
  9. 9. A sequence <ul><li>Oops! </li></ul><ul><li>Perl doesn't have infinite sequences </li></ul>
  10. 10. A sequence <ul><ul><li>Iterators </li></ul></ul>
  11. 11. A sequence <ul><ul><li>curry cycle (@list) { </li></ul></ul><ul><ul><li>my @curr = @list; </li></ul></ul><ul><ul><li>return sub { </li></ul></ul><ul><ul><li>@curr = @list </li></ul></ul><ul><ul><li>unless @curr; </li></ul></ul><ul><ul><li>return shift @curr; </li></ul></ul><ul><ul><li>}; </li></ul></ul><ul><ul><li>} </li></ul></ul>
  12. 12. A sequence <ul><li>my $c = cycle [2.5, 2, 2]; </li></ul>
  13. 13. A sequence <ul><li>my $c = cycle [2.5, 2, 2]; </li></ul><ul><ul><li>say $c->(); # 2.5 </li></ul></ul><ul><ul><li>say $c->(); # 2 </li></ul></ul><ul><ul><li>say $c->(); # 2 </li></ul></ul><ul><ul><li>say $c->(); # 2.5 </li></ul></ul><ul><ul><li>... </li></ul></ul>
  14. 14. A sequence cycle [2.5, 2, 2];
  15. 15. A sequence 10, cycle [2.5, 2, 2];
  16. 16. A sequence mult, 10, cycle [2.5, 2, 2];
  17. 17. (curry)‏ <ul><ul><li>curry mult ($x,$y) { </li></ul></ul><ul><ul><li>$x * $y </li></ul></ul><ul><ul><li>} </li></ul></ul>
  18. 18. (curry)‏ <ul><ul><li>say mult( 3, 4 ); </li></ul></ul><ul><ul><li># 12 </li></ul></ul>
  19. 19. (curry)‏ <ul><ul><li>my $triple = mult(3); </li></ul></ul><ul><ul><li>say $triple->(10); </li></ul></ul><ul><ul><li># 30 </li></ul></ul>
  20. 20. (curry)‏ <ul><ul><li>my $multiply = mult; </li></ul></ul><ul><ul><li>say $multiply->(6, 8); </li></ul></ul>
  21. 21. (curry)‏ <ul><ul><li>my $multiply = &mult; </li></ul></ul><ul><ul><li>my $multiply = mult; </li></ul></ul>
  22. 22. A sequence mult , 10, cycle [2.5, 2, 2];
  23. 23. A sequence scan mult, 10, cycle [2.5, 2, 2];
  24. 24. (Scanning)‏ scan add, 1, [2, 3, 4]; # [1, 3, 6, 10]
  25. 25. A sequence scan mult, 10, cycle [2.5, 2, 2];
  26. 26. A sequence take 12 => scan mult, 10, cycle [2.5, 2, 2];
  27. 27. A sequence say for take 12 => scan mult, 10, cycle [2.5, 2, 2];
  28. 28. A sequence <ul><li>10 </li></ul><ul><li>25 </li></ul><ul><li>50 </li></ul><ul><li>100 </li></ul><ul><li>250 </li></ul><ul><li>500 </li></ul><ul><li>... </li></ul>
  29. 29. How? <ul><li>Iterators (HOP)‏ </li></ul><ul><ul><li>HOP::Stream </li></ul></ul><ul><ul><li>Lazy variables </li></ul></ul>
  30. 30. How? <ul><li>Iterators (HOP)‏ </li></ul><ul><li>FP (scan, take)‏ </li></ul>
  31. 31. How? <ul><li>Iterators (HOP)‏ </li></ul><ul><li>FP (scan, take)‏ </li></ul><ul><li>Sub::Curried </li></ul>
  32. 32. How? <ul><li>Iterators (HOP)‏ </li></ul><ul><li>FP (scan, take)‏ </li></ul><ul><li>Sub::Curried </li></ul><ul><li>Devel::Declare </li></ul>
  33. 33. Devel::Declare <ul><ul><li>curry mult ($x,$y) { </li></ul></ul><ul><ul><li>$x * $y </li></ul></ul><ul><ul><li>} </li></ul></ul>
  34. 34. Devel::Declare <ul><li>New syntax! </li></ul><ul><li>(But better than source filters)‏ </li></ul>
  35. 35. Devel::Declare <ul><li>New syntax! </li></ul><ul><li>(But better than source filters)‏ </li></ul><ul><ul><li>Method declaration </li></ul></ul><ul><ul><li>MooseX::Declare </li></ul></ul><ul><ul><li>Sub::Auto </li></ul></ul>
  36. 36. Devel::Declare <ul><li>New syntax! </li></ul><ul><li>(But better than source filters)‏ </li></ul><ul><ul><li>Currying </li></ul></ul><ul><ul><li>Monads </li></ul></ul><ul><ul><li>Pattern Matching </li></ul></ul><ul><ul><li>List comprehensions </li></ul></ul><ul><ul><li>Functions that work on @arrays and lists </li></ul></ul>
  37. 37. Devel::Declare <ul><li>In Perl! </li></ul><ul><li>(With a bit of scary XS magic)‏ </li></ul><ul><ul><li>hooks into the compiler </li></ul></ul><ul><ul><li>changing the source as you compile </li></ul></ul><ul><ul><li>horrible perl tricks to get methods installed, and braces closed </li></ul></ul><ul><ul><li>mst++, rafl++ </li></ul></ul>
  38. 38. Some light relief
  39. 39. Some light relief Monads
  40. 40. Monads <ul><li>Come from maths </li></ul><ul><li>“ Category theory” </li></ul>
  41. 41. Monads <ul><li>Come from maths </li></ul><ul><li>“ Category theory” </li></ul><ul><li>Very clever people rave about them being useful </li></ul>
  42. 42. Monads <ul><li>Come from maths </li></ul><ul><li>“ Category theory” </li></ul><ul><li>Very clever people rave about them being useful </li></ul><ul><li>Have a reputation for being hard to understand </li></ul>
  43. 43. Monad tutorials
  44. 44. Monad tutorials
  45. 45. Monad tutorials
  46. 46. Monad tutorials
  47. 47. Monad tutorials Step 1: Write Monad Tutorial
  48. 48. Monad tutorials Step 2: ???
  49. 49. Monad tutorials Step 3: Profit!
  50. 50. Monads <ul><li>You already use monads </li></ul>
  51. 51. Monads <ul><li>You already use monads </li></ul><ul><li>YAY! </li></ul>
  52. 52. Monads <ul><li>You already use monads </li></ul><ul><li>Sequences of commands? </li></ul>
  53. 53. Sequencing my $x = 1; my $y = 2; my $z = $x * $y; say “$x * $y = $z”;
  54. 54. Sequencing my $x = 1; my $y = 2; my $z = $x * $y; say “$x * $y = $z”;
  55. 55. Sequencing my $x = 1; my $y = 2; my $z = $x * $y; say “$x * $y = $z”;
  56. 56. Sequencing my @seq = sub { my $x = 1 }, sub { my $y = 2 }, sub { my $z = $x * $y }, sub { say &quot;$x * $y = $z&quot; };
  57. 57. Sequencing my @seq = sub { my $x = 1 }, sub { my $y = 2 }, sub { my $z = $x * $y }, sub { say &quot;$x * $y = $z&quot; }; # Global symbol &quot;$x&quot; requires explicit package name at ...
  58. 58. Nesting my $x = 1; my $y = 2; my $z = $x * $y; say “$x * $y = $z”;
  59. 59. Nesting sub { my $x = 1; sub { my $y = 2; sub { my $z = $x * $y; sub { say &quot;$x * $y = $z&quot;; }->() }->() }->() }->();
  60. 60. Monads made pretty <ul><li>Source filters! </li></ul><ul><ul><li>http://sleepingsquirrel.org/monads/monads.html </li></ul></ul>
  61. 61. Monads made pretty <ul><li>Source filters! </li></ul><ul><ul><li>http://sleepingsquirrel.org/monads/monads.html </li></ul></ul><ul><li>Source tree manipulation (B::OP magic)‏ </li></ul><ul><li>Deparse and source text munging </li></ul>
  62. 62. Monads made pretty <ul><li>We want a syntax like </li></ul><ul><li>mdo { my $x = mbind(1); my $y = mbind(2); my $z = mbind($x + $y); say “$x * $y = $z”; } </li></ul>
  63. 63. Monads made pretty <ul><li>We want a syntax like </li></ul><ul><li>mdo { my $x = mbind(1); my $y = mbind(2); my $z = mbind($x + $y); say “$x * $y = $z”; } </li></ul><ul><li>mdo introduces the block </li></ul><ul><li>mbind gives us a hook to rotate around </li></ul>
  64. 64. Optree munging <ul><li>19: my $x << Just 2; ... n <;> nextstate(main 2078 b.pl:19) v:*,&,$ ->o t <2> left_shift[t3] vK ->u o <0> padsv[$x:2078,2080] sM/LVINTRO ->p s <1> entersub[t2] sKS/TARG,3 ->t - <1> ex-list sK ->s p <0> pushmark s ->q q <$> const(IV 2) sM ->r - <1> ex-rv2cv sK/130 ->- r <$> gv(*Just) s ->s u <;> nextstate(main 2079 b.pl:20) v:*,&,$ ->v </li></ul><ul><li># : mbind (Just 2), sub { my $x = shift; ... }; <;> nextstate(main b.pl:) v:*,&,{,$ -> <@> list K -> <0> pushmark s -> <1> entersub[t2] KS/TARG,3 -> - <1> ex-list K -> <0> pushmark s -> <1> entersub[t1] lKMS/NO(),TARG,INARGS,3 -> - <1> ex-list lK -> <0> pushmark s -> <$> const(IV 2) sM -> - <1> ex-rv2cv sK/130 ->- <$> gv(*Just) s -> - <1> ex-rv2cv sK/2 ->- # mbind instead of >> <$> gv(*mbind) s -> <1> refgen K/1 -> - <1> ex-list lKRM -> <0> pushmark sRM -> <$> anoncode[CV ] lRM -> # ??? set up anon sub # my $x = shift <0> padsv[$x:2078,2080] sM/LVINTRO ->p # the next ; is moved into this new lambda! <;> nextstate(main 2079 b.pl:20) v:*,&,$ ->v </li></ul>
  65. 65. Optree munging <ul><li>19: my $x << Just 2; ... n <;> nextstate(main 2078 b.pl:19) v:*,&,$ ->o t <2> left_shift[t3] vK ->u o <0> padsv[$x:2078,2080] sM/LVINTRO ->p s <1> entersub[t2] sKS/TARG,3 ->t - <1> ex-list sK ->s p <0> pushmark s ->q q <$> const(IV 2) sM ->r - <1> ex-rv2cv sK/130 ->- r <$> gv(*Just) s ->s u <;> nextstate(main 2079 b.pl:20) v:*,&,$ ->v </li></ul><ul><li># : mbind (Just 2), sub { my $x = shift; ... }; <;> nextstate(main b.pl:) v:*,&,{,$ -> <@> list K -> <0> pushmark s -> <1> entersub[t2] KS/TARG,3 -> - <1> ex-list K -> <0> pushmark s -> <1> entersub[t1] lKMS/NO(),TARG,INARGS,3 -> - <1> ex-list lK -> <0> pushmark s -> <$> const(IV 2) sM -> - <1> ex-rv2cv sK/130 ->- <$> gv(*Just) s -> - <1> ex-rv2cv sK/2 ->- # mbind instead of >> <$> gv(*mbind) s -> <1> refgen K/1 -> - <1> ex-list lKRM -> <0> pushmark sRM -> <$> anoncode[CV ] lRM -> # ??? set up anon sub # my $x = shift <0> padsv[$x:2078,2080] sM/LVINTRO ->p # the next ; is moved into this new lambda! <;> nextstate(main 2079 b.pl:20) v:*,&,$ ->v </li></ul>KABOOM
  66. 66. Source deparsing <ul><li>Works surprisingly well </li></ul>
  67. 67. Source deparsing <ul><li>Works surprisingly well </li></ul><ul><li>for trivial cases </li></ul><ul><li>(a bit fragile)‏ </li></ul>
  68. 68. Source deparsing <ul><li>Works surprisingly well </li></ul><ul><li>for trivial cases </li></ul><ul><li>(a bit fragile)‏ </li></ul><ul><li>though localised to mdo { ... } </li></ul>
  69. 69. Devel::Declare <ul><li>Even nicer syntax </li></ul><ul><li>mdo { mbind $x = 1; mbind $y = 2; mbind $z = $x + $y; say “$x * $y = $z”; } </li></ul>
  70. 70. Devel::Declare <ul><li>And cuter implementation: </li></ul><ul><li>mdo { mbind $x = 1; mbind $y = 2; mbind $z = $x + $y; say “$x * $y = $z”; } </li></ul>
  71. 71. Devel::Declare <ul><li>The problem: </li></ul><ul><li>mdo { mbind 1, sub { my $x = shift; mbind 2, sub { my $y = shift; mbind $x + $y, sub { my $z = shift; say “$x * $y = $z”; } ... </li></ul>
  72. 72. Devel::Declare <ul><li>No need to count nesting: </li></ul><ul><li>scope_inject </li></ul><ul><li>Scope::Guard </li></ul><ul><li>Use to inject a ; at the end of method declarations: </li></ul><ul><li>method foo ($x) { print $x; } # look Ma, no semicolon! </li></ul>
  73. 73. Devel::Declare <ul><li>mbind's scope_inject adds a “}” </li></ul><ul><li>mdo { mbind 1, sub { my $x = shift; mbind 2, sub { my $y = shift; mbind $x + $y, sub { my $z = shift; say “$x * $y = $z”; } # adds a closing brace } </li></ul>
  74. 74. Devel::Declare <ul><li>mbind's scope_inject adds a “}” </li></ul><ul><li>mdo { mbind 1, sub { my $x = shift; mbind 2, sub { my $y = shift; mbind $x + $y, sub { my $z = shift; say “$x * $y = $z”; } } # adds a closing brace } </li></ul>
  75. 75. Devel::Declare <ul><li>mbind's scope_inject adds a “}” </li></ul><ul><li>mdo { mbind 1, sub { my $x = shift; mbind 2, sub { my $y = shift; mbind $x + $y, sub { my $z = shift; say “$x * $y = $z”; } } } # adds a closing brace } </li></ul>
  76. 76. Devel::Declare <ul><li>mbind's scope_inject adds a “}” </li></ul><ul><li>mdo { mbind 1, sub { my $x = shift; mbind 2, sub { my $y = shift; mbind $x + $y, sub { my $z = shift; say “$x * $y = $z”; } } } } # closes block </li></ul>
  77. 77. So... <ul><li>We can now sequence commands! </li></ul><ul><li>mdo { mbind $x = 1; mbind $y = 2; mbind $z = $x + $y; say “$x * $y = $z”; } </li></ul>
  78. 78. So... <ul><li>We can now sequence commands! </li></ul><ul><li>YAY? </li></ul>
  79. 79. So... <ul><li>We can now sequence commands! </li></ul><ul><li>OK, so this was big news in Haskell in 1990s </li></ul>
  80. 80. So... <ul><li>We can now sequence commands! </li></ul><ul><li>OK, so this was big news in Haskell in 1990s </li></ul><ul><li>Imperative languages have always done this </li></ul>
  81. 81. What else can monads do ? <ul><li>Sequencing </li></ul><ul><li>mdo { mbind $x = 1; mbind $y = 2; mbind $z = $x + $y; say “$x * $y = $z”; } </li></ul>
  82. 82. What else can monads do ? <ul><li>Sequencing </li></ul><ul><li>mdo { mbind $x = 1; mbind $y = 2; mbind $z = $x + $y; say “$x * $y = $z”; } </li></ul>
  83. 83. What else can monads do ? <ul><li>Sequencing </li></ul><ul><li>mdo { mbind $x = 1 ; mbind $y = 2 ; mbind $z = $x + $y ; say “$x * $y = $z”; } </li></ul>
  84. 84. What else can monads do ? <ul><li>Sequencing </li></ul><ul><li>mdo { mbind $x = 1 ; mbind $y = 2 ; mbind $z = $x + $y ; say “$x * $y = $z”; } </li></ul><ul><li>Programmable semicolon! </li></ul>
  85. 85. Maybe <ul><li>Success/Failure </li></ul><ul><li>mdo (Maybe) { mbind $FH = m_open('<', $file) ; mbind $line = <$FH> ; mbind $val = lookup(h, $line) ; say “Found $val!”; } </li></ul>
  86. 86. Maybe <ul><li>Success/Failure </li></ul><ul><li>mdo (Maybe) { mbind $FH = m_open('<', $file) ; mbind $line = <$FH> ; mbind $val = lookup(h, $line) ; say “Found $val!”; } </li></ul><ul><li>Will give up if can't open file, read a line from it, or look it up in a hash </li></ul>
  87. 87. Maybe <ul><li>Success/Failure </li></ul><ul><li>mdo (Maybe) { mbind $FH = m_open('<', $file) ; mbind $line = <$FH> ; mbind $val = lookup(h, $line) ; say “Found $val!”; } </li></ul><ul><li>Compare chain of if (foo) { if (bar) { ... </li></ul><ul><li>or eval { ... } </li></ul>
  88. 88. Maybe $FH = open($file)‏ $line = <$FH> $val = lookup ( $line )‏ say “Found $val”
  89. 89. Maybe $FH = open($file)‏ $line = <$FH> $val = lookup ( $line )‏ say “Found $val”
  90. 90. Sequence
  91. 91. Maybe ? ? ?
  92. 92. Multiple (List)‏
  93. 93. List $x = [1..10] $y = [1..10] guard $x+$y == 10 say “$x+$y=10”
  94. 94. List <ul><li>Cartesian product </li></ul><ul><li>mdo { mbind $x = [1..10] ; mbind $y = [1..10] ; mbind guard $x+$y == 10 ; say “$x+$y=10”; } </li></ul><ul><li>Run every $x against every $y and filter </li></ul>
  95. 95. List <ul><li>Cartesian product </li></ul><ul><li>mdo { mbind $x = [1..10] ; mbind $y = [1..10] ; mbind guard $x+$y == 10 ; say “$x+$y=10”; } </li></ul><ul><li>1+9=10 </li></ul><ul><li>2+8=10 </li></ul><ul><li>... </li></ul>
  96. 96. List <ul><li>Cartesian product </li></ul><ul><li>mdo { mbind $x = [1..10] ; mbind $y = [1..10] ; mbind guard $x+$y == 10 ; say “$x+$y=10”; } </li></ul><ul><li>just like SQL </li></ul><ul><li>or LINQ </li></ul>
  97. 97. List comprehension <ul><li>More compact syntax </li></ul><ul><li>mcomp ($x <- [1..10]; $y <- [1..10]; $x+y==10) { say “$x+$y=10” } </li></ul>
  98. 98. List <ul><li>mdo { mbind $x = [1..10] ; mbind $y = [1..10] ; mbind guard $x+$y == 10; say “$x+$y=10”; } </li></ul><ul><li>We're actually calling mbind on a list </li></ul>
  99. 99. List <ul><li>mdo { mbind $x = [1..10] ; mbind $y = [1..10] ; mbind guard $x+$y == 10; say “$x+$y=10”; } </li></ul><ul><li>We're actually calling mbind on a list </li></ul><ul><li>autobox </li></ul>
  100. 100. Perl++ <ul><li>Not really a functional language... </li></ul><ul><li>But you can take it surprisingly far </li></ul><ul><li>(CPAN++)‏ </li></ul>
  101. 101. What else can I do with monads? <ul><li>Parsing </li></ul><ul><li>Error handling </li></ul><ul><li>SQL generation </li></ul><ul><li>Continuations (real resumable ones)‏ </li></ul>
  102. 102. Wants monads now! <ul><li>Techniques are valuable now </li></ul><ul><li>Nicely wrapped implementation will be ready soon.... </li></ul>
  103. 103. Thanks! <ul><li>questions? </li></ul>

×