Functional Pe(a)rls - the Purely Functional Datastructures edition

Post on 01-Jul-2015

746 views 0 download

description

All new material, this time about one of the fundamental functional datastructures, the Linked List, and the overview of an implementation in Moosey Perl.This covers some of the same material as https://github.com/osfameron/pure-fp-book but perhaps with more explanation (and covering much less material - it was only a 20 minute talk)

Transcript of Functional Pe(a)rls - the Purely Functional Datastructures edition

Functional Pe(a)rls

osfameron @ IPW2011, Turinosfameron @ IPW2011, Turinthe “purely functional data structures” the “purely functional data structures”

editionedition

http://www.fickr.com/photos/jef_saf/3493852795/

previously on Functional Pe(a)rls...

(IPW, LPW, YAPC::EU, nwe.pm)currying

operator references: op(+)Acme::MonadsDevel::Declare

C I A O

C I A O

vs.

0 1 2 3

C I A O

0 1 2 3

0th element

C I A O

0 1 2 3

0th element

M I A OM I A OM I A O

0 1 2 3

0th element

M I A OM I A OM I A O

no kittens were harmed during the making of

this presentation

0 1 2 3

2nd element

M I A O

0 1 2 3

4th element

M I A O

0 1 2 3

max: 3

M I A O

0 1 2 3

max: 3

M I A O

0 1 2 3

max: 4

M I A O W

4th element

4

0 1 2 3

max: 3

M I A O …

100,000

0 1 2 3

max: 3

M I A O

0 1 2 3

max: 4

M I A O W4

0 1 2 3

max: 5

M I A O W !4 5

40 1 2 3

max: 4

M I A O W

0 1 2 3

max: 5

M I A O W !4 5

C I A O

C I A O

vs.

Arrays

C I A O

C I A O

vs.

Perl @arrays“dynamic array”

C I A O

C I A O

C I A O

Head

C I A O

Tail

C I A O

C I A O

I A O

A O

O

C I A O

0th

C A O

nth - 1

I

C A O

nth[2]?

I

nth[1]?

C A OI

nth[0]!nth[2]?

C I A O ?

C I A O ?● tail “ciao” → “iao”

C I A O ?● tail “ciao” → “iao”● tail “iao” → “ao”● tail “ao” → “o”● tail “o” → ?

C I A O ?● tail “ciao” → “iao”● tail “iao” → “ao”● tail “ao” → “o”● tail “o” → “” (the empty string)

C I A O

Head

List =

Tail(another List)

or...

Here comes the science^wPerl!

use MooseX::Declare;

BEGIN { role_type 'List' }

role List { requires 'head'; requires 'tail';}

Moose(X::Declare)

List::Link

class List::Link with List { has head => (

is => 'ro', isa => 'Any'

); has tail => (

is => 'ro', isa => 'List'

), }

List::Link

class List::Link with List { has head => (

is => 'ro', isa => 'Any'

); has tail => (

is => 'ro', isa => 'List'

), }

List::Link

class List::Link with List { has head => (

is => 'ro', isa => 'Any'

); has tail => (

is => 'ro', isa => 'List'

), }

List::Empty

class List::Empty with List { method head {

die "Can't take head of empty list!" } method tail { die "Can't take tail of empty list!" } }

So we can write:

my $list = List::Link->new( head => 'c', tail => List::Link->new( head => 'i', tail => List::Link->new(...

Sugar!

my $list = List->fromArray(qw/ c i a o /);

Multimethods

use MooseX::MultiMethods;

multi method fromArray ($class:) { return List::Empty->new; }

Multimethods

use MooseX::MultiMethods;

multi method fromArray ($class:) { return List::Empty->new; }

Multimethods multi method fromArray ($class: $head, @tail) { return List::Link->new( head => $head, tail => $class->fromArray(@tail), ); }

Eeek! Recursion!

my $list = List::fromArray(1..1000000);

Eeek! Recursion!

my $list = List::fromArray(1..1000000);

Deep recursion on subroutine "List::fromArray" at foo.pl line 20

Eeek! Recursion! multi method fromArray ($class: $head, @tail) { return List::Link->new( head => $head, tail => $class->fromArray(@tail), ); }

Eeek! Recursion!

fromArray

Eeek! Recursion!

fromArray

List::Link->new(..., fromArray)

Eeek! Recursion!

fromArray

List::Link->new(..., fromArray)

List::Link->new(..., fromArray)

Eeek! Recursion!

fromArray

List::Link->new(..., fromArray)

List::Link->new(..., fromArray)

List::Link->new(..., fromArray)

Eeek! Recursion!

fromArray

List::Link->new(..., fromArray)

List::Link->new(..., fromArray)

List::Link->new(..., fromArray)

List::Link->new(..., fromArray)

Eeek! Recursion!

fromArray

List::Link->new(..., fromArray)

List::Link->new(..., fromArray)

List::Link->new(..., fromArray)

List::Link->new(..., fromArray) $list=

Eeek! Recursion!

fromArray

List::Link->new(..., fromArray)

List::Link->new(..., fromArray)

List::Link->new(..., fromArray) $list=

Eeek! Recursion!

fromArray

List::Link->new(..., fromArray)

List::Link->new(..., fromArray) $list=

Eeek! Recursion!

fromArray

List::Link->new(..., fromArray) $list=

Eeek! Recursion!

fromArray $list=

Eeek! Recursion!

no warnings 'recursion';$DB::deep = 100_000_000;

Eeek! Recursion!

no warnings 'recursion';$DB::deep = 100_000_000;

Papering over the cracks

Tail Call Elimination

Sub::Call::TailSub::Call::Recur

by nothingmuch

Tail call elimination

fromArray

Tail call elimination

List::Link->new(..., fromArray)

Tail call elimination

List::Link->new(..., fromArray)

Tail call elimination

List::Link->new(..., fromArray)

Tail call elimination

List::Link->new(..., fromArray)

Tail call elimination

List::Link->new(..., fromArray) $list=

Tail Call Elimination

use Sub::Import 'Sub::Call::Tail' tail => { -as => 'tail_call' };

multi method fromArray ($self: $head, @tail) { tail_call List::Link->new( head => $head, tail => $self->fromArray(@tail), );}

Indexing into List

multi method nth (List::Empty $self: Int $pos)

{ die "Can't index into an Empty list"; }

Indexing into List

multi method nth (Int $pos where { $_ == 0 })

{ return $self->head; }

Indexing into List

multi method nth (Int $pos where { $_ > 0 })

{ tail_call $self->tail->nth( $pos - 1 ); }

C I A O

M

C I A O

M W

C I A O

M WMutation leads to bugs (and misspellings!)

C I A O

M WI A O

C I A O

C I B

C I A O

C I B

Copy everything upstream of a changeDownstream of changes can be shared

C I A O

C I B

Doubly linked lists have no downstream!

O

pure-fp-book

● https://github.com/osfameron/pure-fp-book● Purely Functional Data Structures for the...

● Impure● Perl Programmer● Working Programmer● Mutable, Rank-Scented Many