This document discusses arrows in Perl. It describes how arrows generalize monads by allowing composition of functions with arbitrary signatures. It provides examples of implementing arrow classes in Perl, including using subroutines as arrows and implementing arrow operators like first, split, and parallel composition. It also discusses how arrows form a premonoidal category and relates arrows to monads.
23. Monad Arrow
(Haskell )
mb
f
a
Arrows
f :: m b c b
a
24. Arrows
arr >>> first ↝
arr :: a -> b -> (a ↝ b)
>>> :: (a ↝ b) -> (b ↝ c) -> (a ↝ c)
first :: (a ↝ b) -> (a × c ↝ b × c)
25. Arrow
package Arrow;
sub arr {
my ($class, $code) = @_;
die "not implemented";
}
sub first {
my $self = shift;
die "not implemented";
}
sub next {
my ($self, $arrow) = @_;
die "not implemented";
}
26. first
a↝b a b
>>>
arr ↝
a f b a arr f :: a ↝ b
b
g arr arr f >>> arr g :: a ↝ c
arr g :: b ↝ c
g.f
c c
27. first
Arrow ↝
a c a×c
f :: a↝b g :: c↝d f *** g :: a×c↝b×d
b d b×d
28. (f *** g) >>> (f’ *** g’) (f >>> f’) *** (g >>> g’)
f g f g
f’ g’ f’ g’
29. (f *** g) >>> (f’ *** g’) (f >>> f’) *** (g >>> g’)
f g f g
f’ g’ f’ g’
30. premonoidal category
f ⋉ id = first f a×b a×b
id ⋊ f = second f
f ⋉ id
a’×b (f>>>f’) ⋉ id
f’ ⋉ id
a’’×b a’’×b
31. premonoidal category
f ⋉ id = first f a×b a×b
id ⋊ f = second f
f ⋉ id
a’×b (f>>>f’) ⋉ id
f’ ⋉ id
a’’×b a’’×b
32. central
f *** g ≡ first f >>> second g
first f >>> second - = second - >>> first f
first - >>> second f = second f >>> first -
f central
arr f central
f |x g ≡ first f >>> second (arr g)
( 10.2)
33. Freyd category
premonoidal category
(central central )
a -> b Arrow a ↝ b
arr Freyd category
35. second ***
sub second {
my $self = shift;
my $swap = (ref $self)->arr(sub { $_[1], $_[0] });
$swap->next($self->first)->next($swap);
}
sub parallel {
my ($self, $arrow) = @_;
$self->first->next($arrow->second);
}
fst f >>> snd g
id g
C C D
f id
A B B
36. &&&
sub split {
my ($self, $arrow) = @_;
(ref $self)->arr(sub {
my $args = [@_];
$args, $args;
})->next($self->parallel($arrow));
}
A A
arr id
arr id
arr <id, id>
f g A arr π
A×A arr π’
A
f &&&g f g
f *** g
arr π arr π’
B
arr π
B×C arr π’
C B B×C C
43. first
a π a×c π’ c
f f×return return
π π’
mb mb×mc mc
φ
m(b×c)
44. package Arrow::Kleisli;
use parent qw/Arrow/;
sub _safe_name($) {
my $name = shift;
$name =~ s|::|__|g;
return "__$name";
}
sub new_class {
my $class = shift;
my ($monad) = @_;
my $class_name = "$class::" . _safe_name($monad);
unless ($class_name->isa($class)) {
no strict qw/refs/;
@{"$class_name::ISA"} = ($class);
*{"$class_name::monad"} = sub { $monad };
*{"$class_name::new_class"} = sub {
die "Don't call the new_class() method from sub classes.";
};
}
return $class_name;
}
sub monad { die "Implement this method in sub classes" }
...
45. sub new {
my ($class, $kleisli) = @_;
bless $kleisli, $class;
}
sub arr {
my ($class, $code) = @_;
$class->new(sub {
$class->monad->unit($code->(@_));
});
}
sub next {
my ($self, $arrow) = @_;
(ref $self)->new(sub {
my @v = @_;
$self->(@v)->flat_map($arrow);
});
}
46. sub first {
my $self = shift;
my $class = (ref $self);
my $monad = $class->monad;
$class->new(sub {
my ($args1, $args2) = @_;
$monad->sequence(
$self->(@$args1)->map(sub {[@_]}),
$monad->unit(@$args2)->map(sub {[@_]}),
);
});
}
47. arr 10
arr π
()
arr 10 &&& arr 2 div
Int×Int Int
arr π’
arr 2
div :: Int×Int ↝ Int = Int×Int → Maybe Int
48. my $class = Arrow::Kleisli->new_class('Data::Monad::Maybe');
my $arrow10 = $class->arr(sub { 10 });
my $arrow2 = $class->arr(sub { 2 });
my $arrow_div = $class->new(sub {
$_[1][0] == 0 ? nothing : just ($_[0][0] / $_[1][0]);
});
my $arrow10_div_2 = $arrow10->split($arrow2)-
>next($arrow_div);
my $maybe = $arrow10_div_2->();
print $maybe->is_nothing ? 'NOTHING' : $maybe->value;
print "n";