monads in perl

92
Monads in Perl 本間 雅洋 hiratara <[email protected] >

Upload: masahiro-honma

Post on 08-May-2015

3.676 views

Category:

Technology


2 download

DESCRIPTION

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

TRANSCRIPT

Page 1: Monads in perl

Monads in Perl本間 雅洋

hiratara <[email protected]>

Page 2: Monads in perl

About me

d.hatena.ne.jp/hiratara

twitter.com/hiratara

working as a Perl programmer

a fan of Mathematics

a reporter of this YAPC

Page 3: Monads in perl

What are Monads?

Page 4: Monads in perl

Actually, monads are not anything special.

Page 5: Monads in perl

Category theory helps your understanding.

Page 6: Monads in perl

An arrow is a function

Str Intlength

Regex, Str, Int [Str]split

@str = split /$regex/, $str, $n

$len = length $str

Page 7: Monads in perl

Or represents a method

CGI, Str [Str]param

ClassName CGInew

$cgi = CGI->new

@values = $cgi->param($str)

Page 8: Monads in perl

Connecting two arrows

f g

*

*

*

Page 9: Monads in perl

Connecting two arrows

f g

f;g

sub f;g { g(f(@_)) }

*

*

*sub f;g { my @v = f(@_); g(@v)}

or

Page 10: Monads in perl

The 2 laws of arrows

Page 11: Monads in perl

1) Identitysub id { @_ }

fid id

id;f

f;id

Page 12: Monads in perl

2) Associativity

f g h

(f;g);h

f;(g;h)

Page 13: Monads in perl

Monad consists of Kleisli arrows

Page 14: Monads in perl

Call a diagonal arrowa Kleisli arrow

f

*

M(*)

*

M(*)

Page 15: Monads in perl

Composition of 2 Kleisli arrows

f

*

M(*)

*

M(*) M(*)

*

g

Page 16: Monads in perl

Composition of 2 Kleisli arrows

*

M(*)

*

M(*) M(*)

*

sub f>=>g { f(@_)->flat_map(\&g) }

f>=>g

Page 17: Monads in perl

The 2 laws of Kleisli arrows

(i.e. Monad laws)

Page 18: Monads in perl

1) Identitysub unit { ... }

funit unit

unit>=>f

f>=>unit

*

* * *

*

M(*)

M(*)M(*)M(*)

M(*)

Page 19: Monads in perl

2) Associativity

f g h

f>=>(g>=>h)

*

M(*)

*

M(*)

*

M(*)

*

M(*)

*

M(*)

*

M(*)

*

M(*)

*

M(*)

(f>=>g)>=>h*

M(*)

Page 20: Monads in perl

Consider >=> as“a programmable ;“

Page 21: Monads in perl

Monads are made of3 things

Page 22: Monads in perl

* * * * *

M(*) M(*) M(*) M(*) M(*)

M(M(*)) M(M(*)) M(M(*)) M(M(*)) M(M(*))

1. Nested types M

Page 23: Monads in perl

* * * * *

M(*) M(*) M(*) M(*) M(*)

M(M(*)) M(M(*)) M(M(*)) M(M(*)) M(M(*))

2. A set of arrows to wrap values

unit

unit unit unit unit

unit unit unit

Page 24: Monads in perl

* * * * *

M(*) M(*) M(*) M(*) M(*)

M(M(*)) M(M(*)) M(M(*)) M(M(*)) M(M(*))

3. The operation to lift up arrows

flat_map flat_map flat_map flat_map

flat_map flat_map flat_map flat_map

Page 25: Monads in perl

POINT: M extends values

1 “foo” $objundef

$m1$m2

$m3

$m4

$m5

*

M(*)

Page 26: Monads in perl

POINT: M extends values

1 “foo” $objundef

$m1$m2

$m3

$m4

$m5

*

M(*)

unit(1) unit(“foo”) unit(undef) unit($obj)

unit

Page 27: Monads in perl

ex). List

1 “foo” $objundef

[1] [“foo”] [undef] [$obj]

[1, 2, 3][“foo”, “bar”]

[$obj1, $obj2, $obj3]

[undef, undef]

*

[*]

[]

Page 28: Monads in perl

Monads provide extended values and

its computations

Page 29: Monads in perl

Let’s implement the List Monad

Page 30: Monads in perl

All you have to do isdefine a type and unit

and flat_map.

Page 31: Monads in perl

Implementation of List Monad

sub unit { [$_[0]] }

sub flat_map { my ($m, $f) = @_; [map { @{$f->($_)} } @$m];}

Page 32: Monads in perl

That's all we need!

Page 33: Monads in perl

Well, are you interested in monads law?

The check is left asan exercise :p

Page 34: Monads in perl

Simple usage of List monads

[3, 5]

$nroll_dice

[$n + 1, ..., $n + 6]

sub roll_dice { [map { $_[0] + $_ } 1 .. 6] }

Page 35: Monads in perl

[3, 5]roll_dice’ [4, 5, ..., 9,

6, 7, ..., 11]

flat_map

Simple usage of List monads

sub roll_dice’ { flat_map $_[0] => \&roll_dice }

Page 36: Monads in perl

When we define a monad, it comes with

2 relative functions.

Page 37: Monads in perl

1. map

[3, 5]

$ngo_to_jail

0

[0, 0]map(go_to_jail)

map

Page 38: Monads in perl

1. map

[3, 5]

$ngo_to_jail

0

[0, 0]map(go_to_jail)

mapsub map_ { my ($m, $f) = @_; flat_map $m => sub { unit($f->($_[0])) };}

Page 39: Monads in perl

2. flatten

* * * * *

M(*) M(*) M(*) M(*) M(*)

M(M(*)) M(M(*)) M(M(*)) M(M(*)) M(M(*))

flatten

M(M(M(*))) M(M(M(*))) M(M(M(*))) M(M(M(*))) M(M(M(*)))

flatten flatten flatten flatten

flattenflattenflattenflattenflatten

Page 40: Monads in perl

Implementation of flatten

M(*) *

M(M(*)) M(*)

idflat_map

flatten

Page 41: Monads in perl

Implementation of flatten

M(*) *

M(M(*)) M(*)

idflat_map

flattensub flatten { my $m = shift; flat_map $m => \&id;}

Page 42: Monads in perl

flatten() has an important role on

monads.

Page 43: Monads in perl

Reduction of terms6 3 2 8

2 89

811

19

+

+

+

Page 44: Monads in perl

flatten() plays the same roleM (M (M (M

(M (MM

(MM

M

flatten

flatten

flatten

(*))))

(*)))

(*))

(*)

Page 45: Monads in perl

Can you illustrate another example of

monads?

Page 46: Monads in perl

AnyEvent

Page 47: Monads in perl

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;

Page 48: Monads in perl

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;

Page 49: Monads in perl

$cv representsa future value.

Page 50: Monads in perl

CondVar isn’ta normal value

# !! Can’t write in this way !!

sub some_callback { my $cv = shift;

print $cv, “\n”;}

Page 51: Monads in perl

Retrieve the value from $cv

sub some_callback { my $cv = shift;

print $cv->recv, “\n”;}

Page 52: Monads in perl

Run it !

% perl ./my_great_app.plEV: error in callback (ignoring): AnyEvent::CondVar: recursive blocking wait attempted at ./my_great_app.pl line 9836

Page 53: Monads in perl

You must use cb().sub some_callback { my $cv = shift;

$cv->cb(sub { print $_[0]->recv, "\n"; });}

Page 54: Monads in perl

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; ... }); });}

Page 55: Monads in perl

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; ... }); }); }); });}

Page 56: Monads in perl

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; $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; ... }); }); }); }); }); }); }); }); }); });}

Use cb()

Page 57: Monads in perl

A callback-hell

Page 58: Monads in perl

Coro solves the problem

Page 59: Monads in perl

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); ... };}

Page 60: Monads in perl

Looks perfect!

Page 61: Monads in perl

Though, Coro doessome deep magic

Page 62: Monads in perl

Organize the chaos by the monad pattern

Page 63: Monads in perl

Let’s define a type and unit and flat_map

Page 64: Monads in perl

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);

Page 65: Monads in perl

Which CondVar objsdo normal values correspond to?

Page 66: Monads in perl

We can retrieve a normal value without delay

sub unit { my @values = @_

my $cv = AE::cv; $cv->send(@values);

return $cv;}

Page 67: Monads in perl

Think about flat_map()

$_[0] *

say_hiflat_map

“Hi, $_[0]” after 2 sec

“foo”after 3 sec

Page 68: Monads in perl

Think about flat_map()

“foo”

“Hi, foo”say_hi

$name

“Hi, foo”

3 sec

2 sec

5 sec

$name->flat_map(\&say_hi)

Page 69: Monads in perl

Implementation of flat_map

sub flat_map { my ($cv, $f) = @_;

$cv->cb(sub { my @values = $_[0]->recv; my $cv = $f->(@values); ... })

return ...}

Page 70: Monads in perl

Implementation of flat_map

sub 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;}

Page 71: Monads in perl

A monad comes with map and flatten

Page 72: Monads in perl

Use the CondVar monad

* * *

CV(*) CV(*) CV(*)

flat_map

next_task1

flat_map

next_task2

$cv

Page 73: Monads in perl

Use the CondVar monad

* * *

CV(*) CV(*) CV(*)

flat_map

next_task1

flat_map

next_task2

$cv

∋ sub some_callback { my $cv = shift;

$cv->flat_map(\&next_task1) ->flat_map(\&next_task2) ->flat_map(\&next_task3) ->flat_map(\&next_task4) ->...}

Page 74: Monads in perl

The CV monad has the continuation 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;});

Page 75: Monads in perl

The CV monad also has the Either monad structure

data Either String a = Left String | Right a

(my $right = AE::cv)->send(“A right value”);(my $left = AE::cv)->croak(“A left value”);

Page 76: Monads in perl

Handle exceptions in flat_map

... my $result = AE::cv; $cv->cb(sub { my @r = eval { $_[0]->recv }; return $result->croak($@) if $@; my $cv = $f->(@r); ... }); ...

Left l >>= _ = Left l Right r >>= f = f r

Page 77: Monads in perl

sub fail { my @values = @_

my $cv = AE::cv; $cv->croak(@values);

return $cv;}

Define subs to handle errors

Page 78: Monads in perl

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->($@); ... }); ...

Page 79: Monads in perl

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 { ...});

Page 80: Monads in perl

Does everything go well?

Page 81: Monads in perl

NO

Page 82: Monads in perl

Concurrency

CV(*), CV(*) CV(*, *)

Page 83: Monads in perl

Concurrency

CV(*), CV(*) CV(*, *)sequence

Page 84: Monads in perl

There’re no alchemy.

CV(*, *) CV(*, *)

*, * *, *id

map

Oops!

Page 85: Monads in perl

Define it directlysub sequence { my ($cv1, $cv2) = @_;

$cv1->flat_map(sub { my @v1 = @_; $cv2->flat_map(sub { my @v2 = @_; unit(@v1, @v2); }); });}

Page 86: Monads in perl

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 = @_; ...

Page 87: Monads in perl

Back to the hell

Page 88: Monads in perl

Haskell’s do expression

do v1 <- cv1 v2 <- cv2 v3 <- cv3 v4 <- cv4 ...

return (v1, v2, v3, v4, ...)

Page 89: Monads in perl

The for comprehension

Data::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, ... };};

Page 90: Monads in perl

sub sequence { my ($cv1, $cv2) = @_;

$cv1->flat_map(sub { my @v1 = @_; $cv2->flat_map(sub { my @v2 = @_; unit(@v1, @v2); }); });}

ex). Better implementation of sequence

Page 91: Monads in perl

sub sequence { my ($cv1, $cv2) = @_;

Data::Monad::Base::Sugar::for { pick \my @v1 => sub { $cv1 }; pick \my @v2 => sub { $cv2 }; yield { @v1, @v2 }; };}

ex). Better implementation of sequence

Page 92: Monads in perl

Conclusion

A monad is made of a type, flat_map, unit

Consider AE::cv as a monad

CondVar monads save you from a callback hell

https://github.com/hiratara/p5-Data-Monad