line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# (hack) the next line produces an eval that works in *main::* lexical scope: |
2
|
2
|
|
|
2
|
|
416
|
*Sub::Lambda::evaluate = sub { eval $_[0] }; |
3
|
|
|
|
|
|
|
|
4
|
2
|
|
|
2
|
|
38495
|
use strict; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
78
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
package Sub::Lambda; |
7
|
2
|
|
|
2
|
|
1892
|
use Memoize; |
|
2
|
|
|
|
|
5523
|
|
|
2
|
|
|
|
|
103
|
|
8
|
|
|
|
|
|
|
|
9
|
2
|
|
|
2
|
|
16
|
use base qw(Exporter); |
|
2
|
|
|
|
|
8
|
|
|
2
|
|
|
|
|
198
|
|
10
|
|
|
|
|
|
|
our @EXPORT = qw(fn ap); |
11
|
|
|
|
|
|
|
|
12
|
2
|
|
|
2
|
|
12
|
use vars qw($VERSION); |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
1031
|
|
13
|
|
|
|
|
|
|
$VERSION = '0.02'; |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
=head1 NAME |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
Sub::Lambda - syntactic sugar for lambdas in Perl |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
=head1 SYNOPSIS |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
use Sub::Lambda; |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
*plus = fn a => fn b => '$a + $b'; |
25
|
|
|
|
|
|
|
my $minus = fn a => fn b => q{ $a - $b }; |
26
|
|
|
|
|
|
|
*flip = fn f => fn a => fn b => ap qw(f b a); |
27
|
|
|
|
|
|
|
*sum = fn h => -t => q{ @t ? $h+sum(@t) : ($h || 0) }; |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
print plus(1)->(2) . "\n"; # 3 = 1 + 2 |
30
|
|
|
|
|
|
|
print $minus->(10)->(5) . "\n"; # 5 = 10 - 5 |
31
|
|
|
|
|
|
|
print flip($minus)->(10)->(5) . "\n"; # -5 = 5 - 10 |
32
|
|
|
|
|
|
|
print sum(1,2,3,4) . "\n"; # 10 = 1+2+3+4 |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
my $fac = fn f => fn n => q{ ($n<1) ? 1 : $n*$f->($n-1) }; |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
my $Y = fn m => ap( |
37
|
|
|
|
|
|
|
(fn f => ap m => fn a => ap f => f => a => ()) => |
38
|
|
|
|
|
|
|
(fn f => ap m => fn a => ap f => f => a => ()) |
39
|
|
|
|
|
|
|
); |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
print $Y->($fac)->(5) . "\n"; # 120 = 5! |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
=head1 DESCRIPTION |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
This module provides syntactic sugar for lambda abstractions and |
47
|
|
|
|
|
|
|
applications. Perl supports lambdas through subroutine |
48
|
|
|
|
|
|
|
references. You can write things like the curried addition: |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
sub { my ($x) = @_; sub { my ($y) = @_; $x + $y } } |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
However, this is not very convenient nor readable for more involved lambda |
53
|
|
|
|
|
|
|
expressions. Contrast this with the sugared syntax for the same function: |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
fn x => fn y => q{ $x + $y } |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
If you would like even more convenience at the expense of somewhat unclear |
58
|
|
|
|
|
|
|
semantics, check out the experimental L module, with |
59
|
|
|
|
|
|
|
which you could write: |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
( \x -> \y -> {$x+$y} ) |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
=head2 METHODS |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
=over |
68
|
|
|
|
|
|
|
=cut |
69
|
|
|
|
|
|
|
|
70
|
17
|
|
|
17
|
|
88
|
sub _neat ($) { /^\-?[a-zA-Z]\w*$/ }; |
71
|
13
|
|
|
13
|
|
22
|
sub _var ($) { local $_=$_[0]; s/^/\$/; s/^\$\-/@/; $_ } |
|
13
|
|
|
|
|
40
|
|
|
13
|
|
|
|
|
21
|
|
|
13
|
|
|
|
|
43
|
|
72
|
5
|
|
|
5
|
|
11
|
sub _vars (@) { map {_var $_} grep {_neat $_} @_ } |
|
5
|
|
|
|
|
11
|
|
|
5
|
|
|
|
|
11
|
|
73
|
22
|
|
|
22
|
|
72
|
sub _expr (@) { '(' . (join ',', @_) . ')' } |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
=item fn(pattern => q{ body }) |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
Models lambda abstraction. In list context, outputs the Perl code for |
78
|
|
|
|
|
|
|
a lambda with a given pattern and body. In scalar context, returns a |
79
|
|
|
|
|
|
|
subroutine reference. This context trick allows the sub to be compiled in a |
80
|
|
|
|
|
|
|
one-step B, which appears to be necessary to make sure Perl |
81
|
|
|
|
|
|
|
gets the variable scoping right. Note that this means the end user has |
82
|
|
|
|
|
|
|
to make sure that the functions are called in |
83
|
|
|
|
|
|
|
a scalar context! When in doubt, use C. |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
The basic pattern is just a single variable name; an incrementor can |
86
|
|
|
|
|
|
|
be written as: |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
fn(x => '$x + 1')->(1) # =2 |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
Prefixing with a dash captures lists of arguments: |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
fn(-x => 'scalar(@x)')->(1,2,3,4,5) #= 5 |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
Multiple arguments are allowed too: |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
(fn qw(a b) => '$a+$b')->(1, 2) #= 3 |
97
|
|
|
|
|
|
|
(fn qw(h -t) => '{$h=>[@t]}')->(1,2,3,4) #= {1 => [2,3,4]} |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
Currying is possible too: |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
(fn a => fn b => '$a+$b')->(1)->(2) #= 3 |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
Here are some translation examples: |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
Scheme Perl |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
(lambda (x) (f x)) (fn x => 'f($x)') |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
(lambda x (f x)) (fn -x => 'f(\@x)') |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
(lambda (x y z) (f x y z)) (fn x => y => z => q{ f($x,$y,$z) }) |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
(lambda (h . t) (f h t)) (fn h => -t => q{ f($h, \@t) }) |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
... |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
Haskell |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
\f -> \a -> \b -> f b a (fn f=>fn a=>fn b=>q{$f->($b)->($a)}) |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
B nesting in the following way: |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
fn a => q{ fn b => '$a+$b' } |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
In this example C<$a+$b> will be compiled outside of the lexical scope |
126
|
|
|
|
|
|
|
where C was defined, hence the function will not work. |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
=cut |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
sub fn (@) { |
131
|
|
|
|
|
|
|
my $body = pop; |
132
|
|
|
|
|
|
|
my $tmpl = _expr _vars @_; |
133
|
|
|
|
|
|
|
my $code = qq{sub { my $tmpl = \@_; $body }}; |
134
|
|
|
|
|
|
|
return wantarray ? $code : evaluate($code); |
135
|
|
|
|
|
|
|
} |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
=item ap(@expressions) |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
Models application. Applies the given expressions to the left, |
141
|
|
|
|
|
|
|
as if with Haskell C. In list context, it generates Perl code, |
142
|
|
|
|
|
|
|
while in scalar context it B's it: |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
print ap(qw(a b c)) # ($a)->($b)->(scalar($c)); |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
The expressions can be pieces of Perl code or neat variable names |
147
|
|
|
|
|
|
|
(C standing for C<$x> and C<-x> for C<@x>). |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
C is useful as a shorthand in cases like this: |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
fn f => fn a => fn b => q{ $f->($b)->($a) } |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
Expressed with C it reads: |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
fn f => fn a => fn b => ap qw(f b a) |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
With B and parentheses one can write arbitrarily complex |
158
|
|
|
|
|
|
|
lambda expressions. |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
=cut |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
sub ap (@) { |
163
|
5
|
100
|
|
5
|
1
|
84
|
my @args = map {_neat $_ ? _var $_ : $_} @_; |
|
12
|
|
|
|
|
20
|
|
164
|
5
|
|
|
|
|
12
|
$args[-1] = "scalar" . _expr $args[-1]; |
165
|
5
|
|
|
|
|
8
|
my $code = join "->", map { _expr $_ } @args; |
|
12
|
|
|
|
|
19
|
|
166
|
5
|
50
|
|
|
|
127
|
return wantarray ? $code : evaluate($code); |
167
|
|
|
|
|
|
|
} |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
memoize('fn'); # speedup re-compilations |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
1; |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
__END__ |