File Coverage

blib/lib/fp.pm
Criterion Covered Total %
statement 64 64 100.0
branch 44 50 88.0
condition n/a
subroutine 50 50 100.0
pod 44 44 100.0
total 202 208 97.1


line stmt bran cond sub pod time code
1             package fp;
2              
3 6     6   43938 use strict;
  6         12  
  6         225  
4 6     6   32 use warnings;
  6         11  
  6         323  
5              
6             our $VERSION = '0.03';
7              
8             ## import routine
9             ## --------------------------------------------------
10             # NOTE:
11             # every effort has been made with import
12             # subroutine to not use the assignment
13             # statement, but since you can't export
14             # without it, it had to be done. I don't
15             # consider this as part of the library
16             # but rather part of the infastructure of
17             # this module.
18             sub import {
19 6     6   30 no strict 'refs';
  6         20  
  6         12816  
20 11     11   112 my $package = shift;
21             # we have to use the build in map
22             # here instead of fp::apply, in
23             # order to get an accurate value
24             # from caller. If we use fp::apply,
25             # it's recursion will cause issues
26             # with that.
27 351         8519 map {
28 351         346 *{(caller())[0] . "::$_"} = \&{"${package}::$_"}
  351         716  
29             } (fp::filter(sub {
30 385     385   362 defined &{"${package}::$_[0]"}
  385         1799  
31             }, (fp::is_not_equal_to(fp::len(fp::tail(@_)), 0) ?
32             fp::tail(@_)
33             :
34             fp::filter(
35 396     396   608 sub { fp::is_not_equal_to("import", fp::head(@_)) },
36 11 50       104 fp::list(keys %{"${package}::"})
  11         110  
37             )))) }
38              
39             ## functional constants
40             ## --------------------------------------------------
41             # boolean constants
42             sub true () { 1 }
43             sub false () { 0 }
44            
45             # empty list constant
46 112     112 1 535 sub nil () { () }
47              
48             ## list operations
49             ## --------------------------------------------------
50             # creation
51             sub list (@);
52 36     36 1 205 sub list (@) { @_ }
53              
54             # emptiness predicates
55 1174 100   1174 1 3851 sub is_empty (@) { @_ ? 0 : 1 }
56 4827 50   4827 1 12668 sub is_not_empty (@) { @_ ? 1 : 0 }
57              
58             # selection
59 6389     6389 1 13546 sub head (@) { $_[0] }
60 5551     5551 1 37400 sub tail (@) { @_[ 1 .. $#_ ] }
61              
62             # selection macros
63 4827 50   4827 1 7319 sub first (@) { is_not_empty(@_) ? head @_ : nil }
64 1771     1771 1 2731 sub second (@) { first tail @_ }
65 4     4 1 8 sub third (@) { second tail @_ }
66 3     3 1 8 sub fourth (@) { third tail @_ }
67 2     2 1 6 sub fifth (@) { fourth tail @_ }
68 1     1 1 5 sub sixth (@) { fifth tail @_ }
69              
70 1098     1098 1 1780 sub reduce (@) { tail @_ }
71              
72             # random access
73             sub nth (@); # pre-declare sub so it can be used in recursion
74             sub nth (@) {
75 12 100   12 1 24 (is_empty(tail @_)) ?
    50          
76             nil
77             :
78             ((head @_) == 0) ?
79             second @_
80             :
81             nth(((head @_) - 1), (reduce tail @_)) }
82            
83             # length
84             sub len (@); # pre-declare sub so it can be used in recursion
85 26 100   26 1 123 sub len (@) { @_ ? 1 + len(reduce @_) : 0 }
86            
87             # end access
88 1     1 1 5 sub end (@) { nth((len(@_) - 1), @_) }
89              
90             # add element to the head of the list
91 2     2 1 23 sub prepend (@) { @_ }
92              
93             # add element to the end of the list
94 2     2 1 5 sub append (@) { ((tail @_), (head @_)) }
95              
96             # combine two lists
97 1     1 1 17 sub combine (@) { @_ }
98              
99             # reverse a list
100             sub rev (@); # pre-declare sub so it can be used in recursion
101             sub rev (@) {
102 6 100   6 1 11 (is_empty @_) ?
103             nil
104             :
105             (rev(reduce @_), (first @_)) }
106              
107             # list membership predicate
108             sub member (@); # pre-declare sub so it can be used in recursion
109             sub member (@) {
110 195 100   195 1 318 (is_empty(tail @_)) ?
    100          
111             false
112             :
113             (is_equal_to((first @_),(second @_))) ?
114             true
115             :
116             member((first @_), (reduce tail @_)) }
117            
118             # make a list into a set (list with unique elements)
119             sub unique (@); # pre-declare sub so it can be used in recursion
120             sub unique (@) {
121 37 100   37 1 64 (is_empty(@_)) ?
    100          
122             nil
123             :
124             (member((first @_), (tail @_))) ?
125             (nil, unique(reduce @_))
126             :
127             ((first @_), unique(reduce @_)) }
128              
129             # unique prepend - returns unique list or original list
130             sub unique_prepend (@) {
131 1 50   1 1 4 (member((first @_), (tail @_))) ?
132             tail @_
133             :
134             prepend(@_) }
135              
136             # unique append - returns unique list or original list
137             sub unique_append (@) {
138 1 50   1 1 3 (member((first @_), (tail @_))) ?
139             tail @_
140             :
141             append(@_) }
142              
143             # unique combine function - takes the whole argument list
144 1     1 1 4 sub unique_combine (@) { unique(@_) }
145              
146             ## set (unique list) operations
147             ## --------------------------------------------------
148              
149             # adjoin a set with mutliple new elements
150 1     1 1 4 sub adjoin (@) { unique(@_) }
151              
152             # union of two sets is a list of all thier unique elements
153 1     1 1 4 sub union (@) { unique(@_) }
154              
155             # intersection of two sets is a list of all elements found in both
156             sub intersection (@); # pre-declare sub so it can be used in recursion
157             sub intersection (@) {
158 12 100   12 1 23 (is_empty(@_)) ?
    100          
159             nil
160             :
161             (member((first @_), (tail @_))) ?
162             ((first @_), intersection(reduce @_))
163             :
164             (nil, intersection(reduce @_)) }
165              
166             # differnce of two sets is a list of elements from the first lists
167             # that are not contained in the second list
168             ## NOTE - this cannot be implemented because of perl's auto-list-flatening
169              
170             # xor of two sets is a list of elements not found in both
171             ## NOTE - this cannot be implemented because of perl's auto-list-flatening
172             ## --------------------------------------------------
173              
174             ## function constructor
175             ## --------------------------------------------------
176             sub function (&);
177 2     2 1 9 sub function (&) { (head @_) }
178              
179             ## --------------------------------------------------
180             # map a function to a list
181             sub apply (@); # pre-declare sub so it can be used in recursion
182             sub apply (@) {
183 15         23 (is_empty(tail @_)) ?
184             nil
185             :
186 18 100   18 1 29 (&{first(@_)}(second @_), apply((first @_), (reduce tail @_))) }
187              
188             # filter a list based on a function
189             sub filter (@); # pre-declare sub so it can be used in recursion
190             sub filter (@) {
191 810         1301 (is_empty(tail @_)) ?
192             nil
193             :
194 835 100   835 1 1443 (&{first(@_)}(second @_)) ?
    100          
195             ((second @_), filter((first @_), (reduce tail @_)))
196             :
197             (nil, filter((first @_), (reduce tail @_))) }
198              
199             ## list reduction functions
200             ## --------------------------------------------------
201             # sum a list of integers
202             sub sum (@); # pre-declare sub so it can be used in recursion
203             sub sum (@) {
204 17 100   17 1 30 (is_empty @_) ?
205             0
206             :
207             first(@_) + sum(reduce @_) }
208              
209             # concatenate a list of strings
210             sub concat (@); # pre-declare sub so it can be used in recursion
211             sub concat (@) {
212 35 100   35 1 61 (is_empty @_) ?
213             ""
214             :
215             first(@_) . concat(reduce @_) }
216            
217             # multiply a list of integers
218             sub product (@); # pre-declare sub so it can be used in recursion
219             sub product (@) {
220 6 100   6 1 9 (is_empty @_) ?
221             1
222             :
223             first(@_) * product(reduce @_) }
224              
225             ## list expansion functions
226             ## --------------------------------------------------
227             # split up a string
228 1     1 1 3 sub explode ($) { (first(@_) =~ /(.)/g) }
229              
230             # split up a multi-digit numeral
231 1     1 1 4 sub slice_by ($) { (first(@_) =~ /\d/g) }
232              
233             # get a range of elements
234 16     16 1 42 sub range ($$) { (first(@_) .. second(@_)) }
235              
236             ## misc. predicates
237             ## --------------------------------------------------
238             # even and odd mutually recursive predicates
239             sub is_even ($) {
240 99 100   99 1 130 (first(@_) <= 0) ?
241             true
242             :
243             is_odd(first(@_) - 1) }
244            
245             sub is_odd ($) {
246 95 100   95 1 122 (first(@_) <= 0) ?
247             false
248             :
249             is_even(first(@_) - 1) }
250            
251             sub is_not_equal_to ($$) {
252 407     407 1 628 (not is_equal_to(@_)) }
253            
254             sub is_equal_to ($$) {
255 570 100   570 1 903 (is_digit(head @_)) ?
256             (head(@_) == tail(@_))
257             :
258             (head(@_) eq tail(@_)) }
259            
260             sub is_digit ($) {
261 573     573 1 798 (first(@_) =~ /\d/) }
262            
263             sub is_whitespace ($) {
264 2     2 1 6 (first(@_) =~ /\s/) }
265            
266             sub is_alpha ($) {
267 4     4 1 12 (first(@_) =~ /[a-zA-Z]/) }
268              
269             1;
270              
271             __END__