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