File Coverage

blib/lib/Data/Monad/Base/Monad.pm
Criterion Covered Total %
statement 77 79 97.4
branch 6 6 100.0
condition 3 3 100.0
subroutine 26 27 96.3
pod 9 9 100.0
total 121 124 97.5


line stmt bran cond sub pod time code
1             package Data::Monad::Base::Monad;
2 17     17   58933 use strict;
  17         34  
  17         481  
3 17     17   82 use warnings;
  17         29  
  17         437  
4 17     17   146 use Scalar::Util ();
  17         28  
  17         334  
5 17     17   10031 use Data::Monad::Base::Sugar;
  17         78  
  17         1261  
6 17     17   9317 use Data::Monad::Base::Util qw(list);
  17         44  
  17         7711  
7              
8             sub unit {
9 0     0 1 0 my ($class, @v) = @_;
10 0         0 die "You should override this method.";
11             }
12              
13             sub flat_map_multi {
14 5     5 1 14 my ($class, $f, @ms) = @_;
15              
16             Data::Monad::Base::Sugar::for {
17 5     5   10 my @args;
18 5         31 for my $i (0 .. $#ms) {
19             # capture each value in each slot of @args
20 13         71 pick +(my $slot = []) => sub { $ms[$i] };
  29         68  
21 13         39 push @args, $slot;
22             }
23 5         50 pick sub { $f->(map { @$_ } @args) };
  36         61  
  98         183  
24 5         42 };
25             }
26              
27             sub map_multi {
28 4     4 1 11 my ($class, $f, @ms) = @_;
29              
30 4     30   34 $class->flat_map_multi(sub { $class->unit($f->(@_)) }, @ms)
  30         63  
31             }
32              
33             sub sequence {
34 1     1 1 2 my $class = shift;
35 1     6   10 $class->map_multi(sub { list @_ } => @_);
  6         18  
36             }
37              
38             sub _welldefined_check {
39 16     16   32 my $self = shift;
40 16 100       125 \&flat_map != $self->can('flat_map') and return;
41 8 100 100     59 \&map != $self->can('map') and \&flatten != $self->can('flatten')
42             and return;
43              
44 7         48 die "You must implement flat_map(), or map() and flatten().";
45             }
46              
47             sub flat_map {
48 4     4 1 771 my ($self, $f) = @_;
49              
50 4         13 $self->_welldefined_check;
51              
52 17     17   93 no strict qw/refs/;
  17         36  
  17         2012  
53 1         12 *{(ref $self) . "::flat_map"} = sub {
54 1     1   2 my ($self, $f) = @_;
55 1         3 $self->map($f)->flatten;
56 1         5 };
57              
58 1         4 $self->flat_map($f);
59             }
60              
61             sub map {
62 7     7 1 716 my ($self, $f) = @_;
63              
64 7         53 $self->_welldefined_check;
65              
66 17     17   86 no strict qw/refs/;
  17         30  
  17         2256  
67 5         29 *{(ref $self) . "::map"} = sub {
68 23     23   51 my ($self, $f) = @_;
69 23     32   111 $self->flat_map(sub { (ref $self)->unit($f->(@_)) });
  32         94  
70 5         25 };
71              
72 5         18 $self->map($f);
73             }
74              
75             sub flatten {
76 5     5 1 2999 my $self_duplexed = shift;
77              
78 5         35 $self_duplexed->_welldefined_check;
79              
80 17     17   87 no strict qw/refs/;
  17         27  
  17         4434  
81 3         16 *{(ref $self_duplexed) . "::flatten"} = sub {
82 7     7   29 my $self_duplexed = shift;
83 7         37 $self_duplexed->flat_map(sub { list @_ });
  2         20  
84 3         17 };
85              
86 3         9 $self_duplexed->flatten;
87             }
88              
89 12     14 1 16 sub ap { (ref $_[0])->map_multi(sub { my $c = shift; $c->(@_) } => @_) }
  12     2   30  
  2         15  
90              
91             sub while {
92 3     3 1 7 my ($self, $predicate, $f) = @_;
93              
94 3         5 my $weaken_loop;
95             my $loop = sub {
96 53     53   87 my @v = @_;
97 53 100       116 $predicate->(@v) ? $f->(@v)->flat_map($weaken_loop)
98             : (ref $self)->unit(@v);
99 3         15 };
100 3         45 Scalar::Util::weaken($weaken_loop = $loop);
101              
102 3         14 $self->flat_map($loop);
103             }
104              
105             1;
106              
107             __END__