-
Notifications
You must be signed in to change notification settings - Fork 2
/
functional.rb
117 lines (96 loc) · 2.04 KB
/
functional.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
module Functional
# a = [[1,2],[3,4]]
# sum = lambda {|x,y| x+y}
# sums = sum|a
# => [3,7]
def apply(enum)
enum.map &self
end
alias | apply
# data = [1,2,3,4]
# sum = lambda {|x,y| x+y}
# total = sum<=data
# => 10
def reduce(enum)
enum.inject &self
end
alias <= reduce
# f = lambda {|x| x*x }
# g = lambda {|x| x+1 }
# (f*g)[2]
# => 9
# (g*f)[2]
# => 5
def compose(f)
if self.respond_to?(:arity) && self.arity == 1
lambda {|*args| self[f[*args]] }
else
lambda {|*args| self[*f[*args]] }
end
end
alias * compose
# product = lambda {|x,y| x*y}
# doubler = product >> 2
def apply_head(*first)
lambda {|*rest| self[*first.concat(rest)]}
end
# difference = lambda {|x,y| x-y }
# decrement = difference << 1
def apply_tail(*last)
lambda {|*rest| self[*rest.concat(last)]}
end
alias >> apply_head # g = f >> 2 -- set first arg to 2
alias << apply_tail # g = f << 2 -- set last arg to 2
# cached_f = +f
def memoize
cache = {}
lambda {|*args|
unless cache.has_key? args
print '*'
cache[args] = self[*args]
end
cache[args]
}
end
alias +@ memoize
end
# Add these functional programming methods to Proc and Method classes.
class Proc; include Functional; end
class Method; include Functional; end
data = [1,2,3,4]
sum = lambda {|x,y| x+y}
puts sum<=data
a = [1,2,3,4,5]
puts (sum<=a)/a.size
factorial = +lambda do |x|
return 1 if x==0
x*factorial[x-1]
end
p factorial[20]
p factorial[10]
p factorial[21]
puts '-------------'
class Module
alias [] instance_method
# Define a instance method with name sym and body f.
# Example: String[:backwards] = lambda { reverse }
def []=(sym, f)
self.instance_eval { define_method(sym, f) }
end
end
#
p String[:reverse].bind("hello").call
class UnboundMethod
alias [] bind
end
#
p String[:reverse]["hello"][]
Enumerable[:average] = lambda do
sum, n = 0.0, 0
self.each {|x| sum += x; n += 1 }
if n == 0
nil
else
sum/n
end
end