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 14     14   71900 use strict;
  14         30  
  14         470  
3 14     14   71 use warnings;
  14         27  
  14         340  
4 14     14   127 use Scalar::Util ();
  14         23  
  14         270  
5 14     14   8176 use Data::Monad::Base::Sugar;
  14         34  
  14         1248  
6 14     14   7630 use Data::Monad::Base::Util qw(list);
  14         33  
  14         6813  
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 19 my ($class, $f, @ms) = @_;
15              
16             Data::Monad::Base::Sugar::for {
17 5     5   12 my @args;
18 5         31 for my $i (0 .. $#ms) {
19             # capture each value in each slot of @args
20 13         95 pick +(my $slot = []) => sub { $ms[$i] };
  29         69  
21 13         169 push @args, $slot;
22             }
23 5         48 pick sub { $f->(map { @$_ } @args) };
  36         56  
  98         190  
24 5         53 };
25             }
26              
27             sub map_multi {
28 4     4 1 14 my ($class, $f, @ms) = @_;
29              
30 4     30   43 $class->flat_map_multi(sub { $class->unit($f->(@_)) }, @ms)
  30         232  
31             }
32              
33             sub sequence {
34 1     1 1 3 my $class = shift;
35 1     6   14 $class->map_multi(sub { list @_ } => @_);
  6         20  
36             }
37              
38             sub _welldefined_check {
39 16     16   30 my $self = shift;
40 16 100       170 \&flat_map != $self->can('flat_map') and return;
41 8 100 100     78 \&map != $self->can('map') and \&flatten != $self->can('flatten')
42             and return;
43              
44 7         65 die "You must implement flat_map(), or map() and flatten().";
45             }
46              
47             sub flat_map {
48 4     4 1 1010 my ($self, $f) = @_;
49              
50 4         16 $self->_welldefined_check;
51              
52 14     14   84 no strict qw/refs/;
  14         23  
  14         1629  
53 1         5 *{(ref $self) . "::flat_map"} = sub {
54 1     1   1 my ($self, $f) = @_;
55 1         3 $self->map($f)->flatten;
56 1         5 };
57              
58 1         3 $self->flat_map($f);
59             }
60              
61             sub map {
62 7     7 1 858 my ($self, $f) = @_;
63              
64 7         61 $self->_welldefined_check;
65              
66 14     14   69 no strict qw/refs/;
  14         21  
  14         1966  
67 5         30 *{(ref $self) . "::map"} = sub {
68 23     23   45 my ($self, $f) = @_;
69 23     32   141 $self->flat_map(sub { (ref $self)->unit($f->(@_)) });
  32         89  
70 5         28 };
71              
72 5         19 $self->map($f);
73             }
74              
75             sub flatten {
76 5     5 1 3286 my $self_duplexed = shift;
77              
78 5         46 $self_duplexed->_welldefined_check;
79              
80 14     14   82 no strict qw/refs/;
  14         24  
  14         4043  
81 3         24 *{(ref $self_duplexed) . "::flatten"} = sub {
82 7     7   28 my $self_duplexed = shift;
83 7         47 $self_duplexed->flat_map(sub { list @_ });
  2         21  
84 3         23 };
85              
86 3         10 $self_duplexed->flatten;
87             }
88              
89 12     14 1 21 sub ap { (ref $_[0])->map_multi(sub { my $c = shift; $c->(@_) } => @_) }
  12     2   35  
  2         22  
90              
91             sub while {
92 1     1 1 3 my ($self, $predicate, $f) = @_;
93              
94 1         1 my $weaken_loop;
95             my $loop = sub {
96 25     25   36 my @v = @_;
97 25 100       51 $predicate->(@v) ? $f->(@v)->flat_map($weaken_loop)
98             : (ref $self)->unit(@v);
99 1         7 };
100 1         14 Scalar::Util::weaken($weaken_loop = $loop);
101              
102 1         6 $self->flat_map($loop);
103             }
104              
105             1;
106              
107             __END__