functions 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/.rspec +3 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +22 -0
- data/README.md +35 -0
- data/Rakefile +8 -0
- data/examples/prelude_lambda.rb +45 -0
- data/examples/prelude_meta.rb +72 -0
- data/examples/spec/prelude_lambda_spec.rb +48 -0
- data/examples/spec/prelude_meta_spec.rb +59 -0
- data/functions.gemspec +19 -0
- data/lib/functions.rb +4 -0
- data/lib/functions/prelude_lambda.rb +5 -0
- data/lib/functions/prelude_lambda/basic.rb +83 -0
- data/lib/functions/prelude_lambda/ext.rb +32 -0
- data/lib/functions/prelude_lambda/math.rb +31 -0
- data/lib/functions/prelude_lambda/sorting.rb +27 -0
- data/lib/functions/prelude_meta.rb +306 -0
- data/lib/functions/shared/ext.rb +6 -0
- data/lib/functions/version.rb +3 -0
- data/performance/prelude_performance.rb +49 -0
- data/spec/prelude_lambda_math_spec.rb +41 -0
- data/spec/prelude_lambda_spec.rb +46 -0
- data/spec/prelude_meta_spec.rb +34 -0
- data/spec/spec_helper.rb +17 -0
- data/test/test_prelude_performance.rb +36 -0
- metadata +76 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Koen Handekyn
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# Functional
|
2
|
+
|
3
|
+
This library facilitates writing code in a more functional style inside Ruby.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'functional'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install functional
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
The library provides two different styles.
|
22
|
+
One style builds on Lambda's and another style uses meta-programming.
|
23
|
+
The lambda style is a bit more pure but is currently just a bit slower in performance.
|
24
|
+
|
25
|
+
### Lambda Style
|
26
|
+
|
27
|
+
### Meta Style
|
28
|
+
|
29
|
+
## Contributing
|
30
|
+
|
31
|
+
1. Fork it
|
32
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
33
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
34
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
35
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'functions'
|
2
|
+
|
3
|
+
module PreludeLambdaUsage
|
4
|
+
|
5
|
+
include Functions::Prelude
|
6
|
+
|
7
|
+
Power = ->(p,x) { x**p }.curry
|
8
|
+
Square = Power.(2)
|
9
|
+
Squares = Map.(Square)
|
10
|
+
Sum_Of_Squares1 = Compose.(Sum).(Squares)
|
11
|
+
Sum_Of_Squares2 = Sum < Squares
|
12
|
+
Sum_Of_Squares = Sum_Of_Squares2
|
13
|
+
|
14
|
+
Inc_With = ->(f, n, m) { n + f.(m) }.curry
|
15
|
+
Sum_Of1 = ->(f,arr) { Foldl.( Inc_With.(f), 0, arr) }.curry
|
16
|
+
Sum_Of2 = ->(f) { ->(arr) { Foldl.( Inc_With.(f), 0, arr) } }
|
17
|
+
Sum_Of = Sum_Of1
|
18
|
+
|
19
|
+
# Average variations
|
20
|
+
Average1 = After.( Parallel.(Sum).(Length) ).( Divide )
|
21
|
+
Average2 = After.( Par.([Sum,Length]) ).( Divide )
|
22
|
+
Average3 = After.( [Sum,Length] ).( Divide )
|
23
|
+
|
24
|
+
# Gcd variations
|
25
|
+
Gcd1 = ->(a, b) {
|
26
|
+
(1..[a,b].min).select { |c| a % c == 0 && b % c == 0 }.max
|
27
|
+
}
|
28
|
+
Gcd2 = ->(a,b) { (Divisors.(a) & Divisors.(b)).max }
|
29
|
+
|
30
|
+
# GcdA variations
|
31
|
+
GcdA1 = Max < Intersect < Map.(Divisors) # litteral translation of the definition
|
32
|
+
GcdA2 = ->(arr) { arr.inject { |a, r| Gcd.(a, r) } } # the gcd of an array as an iteration of the gcd over the elements
|
33
|
+
GcdA3 = ReduceLeft.(Gcd) # the same but written without arguments
|
34
|
+
|
35
|
+
Greatest = Max
|
36
|
+
Common = Intersect
|
37
|
+
Dividers = Map.(Divisors)
|
38
|
+
GcdA4 = Greatest < Common < Dividers
|
39
|
+
|
40
|
+
|
41
|
+
# LcmA variations
|
42
|
+
LcmA1 = ->(arr) { arr.inject { |a, r| Lcm.(a, r) } } # the lcm of an array as an iteration of the lcm over the elements
|
43
|
+
LcmA2 = ReduceLeft.(Lcm) # the same but without arguments
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'functions'
|
2
|
+
|
3
|
+
module PreludeMetaUsage
|
4
|
+
|
5
|
+
include Functions::PreludeMeta
|
6
|
+
|
7
|
+
def power(x, p)
|
8
|
+
x ** p
|
9
|
+
end
|
10
|
+
|
11
|
+
def square(x)
|
12
|
+
power(x, 2)
|
13
|
+
end
|
14
|
+
|
15
|
+
def_map :squares, :square
|
16
|
+
|
17
|
+
def squares_bis(a)
|
18
|
+
map(a, :square)
|
19
|
+
end
|
20
|
+
|
21
|
+
def_map :squares_tris, ->(x) { x**2 }
|
22
|
+
|
23
|
+
define :squares_quater, as: { map: ->(x) { x**2 } }
|
24
|
+
|
25
|
+
define :squares_quinquies, as: { map: :square }
|
26
|
+
|
27
|
+
def_filter :evens, :even?
|
28
|
+
|
29
|
+
# same as above
|
30
|
+
# filter :evens, :even?
|
31
|
+
|
32
|
+
def_filter :odds, ->(x) { ! x.even? }
|
33
|
+
|
34
|
+
define :evens_bis, as: { filter: :even? }
|
35
|
+
|
36
|
+
def_compose :sum_of_squares, :sum, :squares
|
37
|
+
|
38
|
+
def sum_of_squares_bis(a)
|
39
|
+
compose(:sum, :squares, a)
|
40
|
+
end
|
41
|
+
|
42
|
+
define :sum_of_squares_tris, as: { compose: [:sum, :squares] }
|
43
|
+
|
44
|
+
def average_bis(a)
|
45
|
+
after([:sum, :length], :divide, a)
|
46
|
+
end
|
47
|
+
|
48
|
+
define :average_tris, as: { :after => [ :sum_length, :divide ] }
|
49
|
+
|
50
|
+
def_after :average_quater, :sum_length, :divide
|
51
|
+
|
52
|
+
def inc_with(f, n, m)
|
53
|
+
m + f(f).(n)
|
54
|
+
end
|
55
|
+
|
56
|
+
# can this be improved on ?
|
57
|
+
# a definition as composition ?
|
58
|
+
def sum_of(f, a)
|
59
|
+
a.inject(0) { |r, x| r + f(f).(x) }
|
60
|
+
end
|
61
|
+
|
62
|
+
def add(a,b)
|
63
|
+
a+b
|
64
|
+
end
|
65
|
+
|
66
|
+
def_foldl :sum_bis, :add, 0
|
67
|
+
|
68
|
+
define :sum_tris, as: { foldl: [:add, 0]}
|
69
|
+
|
70
|
+
define foldl: [:add, 0], as: :sum_quater
|
71
|
+
|
72
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require_relative '../prelude_lambda'
|
2
|
+
|
3
|
+
include PreludeLambdaUsage
|
4
|
+
|
5
|
+
describe PreludeLambdaUsage, "basic lambda prelude usage" do
|
6
|
+
|
7
|
+
it "sums" do
|
8
|
+
Sum_Of_Squares.([2, 3, 4]).should == 2*2+3*3+4*4
|
9
|
+
Sum_Of.(Square).([2, 3, 1]).should == 2*2+3*3+1*1
|
10
|
+
end
|
11
|
+
|
12
|
+
it "averages" do
|
13
|
+
Average.([2, 3, 8]).should == 4
|
14
|
+
end
|
15
|
+
|
16
|
+
it "flattens" do
|
17
|
+
Flatten.([[1, 2, 3], [2, 3]]).should == [1, 2, 3, 2, 3]
|
18
|
+
end
|
19
|
+
|
20
|
+
it "folds" do
|
21
|
+
Foldl.(->(n, a) { n/a }, 1.0, [1.0, 2.0, 3.0]).should == 1.0/1.0/2.0/3.0
|
22
|
+
Foldr.(->(n, a) { n/a }, 1.0, [1.0, 2.0, 3.0]).should == 1.0/3.0/2.0/1.0
|
23
|
+
end
|
24
|
+
|
25
|
+
it "knows about GCD alternatives" do
|
26
|
+
# test variant implementations
|
27
|
+
Gcd1.(4,8).should == 4
|
28
|
+
Gcd2.(4,8).should == 4
|
29
|
+
GcdA1.([4,8,2]).should eq(2)
|
30
|
+
GcdA2.([4,8,2]).should eq(2)
|
31
|
+
GcdA3.([4,8,2]).should eq(2)
|
32
|
+
GcdA4.([4,8,2]).should eq(2)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "knows about LCM variations" do
|
36
|
+
# test variant implementations
|
37
|
+
LcmA1.([12,9,2]).should eq(36)
|
38
|
+
LcmA2.([12,9,2]).should eq(36)
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
#def bench_sum_of_squares
|
43
|
+
# assert_performance_linear 0.9 do |n| # n is a range value
|
44
|
+
# Sum_Of_Squares.((1..n).to_a)
|
45
|
+
# end
|
46
|
+
#end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require_relative '../prelude_meta'
|
2
|
+
|
3
|
+
include PreludeMetaUsage
|
4
|
+
|
5
|
+
describe PreludeMetaUsage, "basic meta prelude usage" do
|
6
|
+
|
7
|
+
it "squares" do
|
8
|
+
squares([1, 2, 3]).should == [1, 4, 9]
|
9
|
+
squares_bis([1, 2, 3]).should == [1, 4, 9]
|
10
|
+
squares_tris([1, 2, 3]).should == [1, 4, 9]
|
11
|
+
squares_quater([1, 2, 3]).should == [1, 4, 9]
|
12
|
+
squares_quinquies([1, 2, 3]).should == [1, 4, 9]
|
13
|
+
end
|
14
|
+
|
15
|
+
it "evens and odds" do
|
16
|
+
evens([1, 2, 3, 4, 5]).should == [2, 4]
|
17
|
+
evens_bis([1, 2, 3, 4, 5]).should == [2, 4]
|
18
|
+
odds([1, 2, 3, 4, 5]).should == [1, 3, 5]
|
19
|
+
end
|
20
|
+
|
21
|
+
it "takes sums of squares and more" do
|
22
|
+
sum_of_squares([2, 3, 4]).should == 2*2+3*3+4*4
|
23
|
+
sum_of_squares_bis([2, 3, 4]).should == 2*2+3*3+4*4
|
24
|
+
sum_of_squares_tris([2, 3, 4]).should == 2*2+3*3+4*4
|
25
|
+
sum_of(:square, [2, 3, 1]).should == 2*2+3*3+1*1
|
26
|
+
sum_of(->(x) { x*x }, [2, 3, 1]).should == 2*2+3*3+1*1
|
27
|
+
sum([1, 2, 3]).should == 1+2+3
|
28
|
+
sum_bis([1, 2, 3]).should == 1+2+3
|
29
|
+
sum_tris([1, 2, 3]).should == 1+2+3
|
30
|
+
sum_quater([1, 2, 3]).should == 1+2+3
|
31
|
+
end
|
32
|
+
|
33
|
+
it "takes averages" do
|
34
|
+
average([2, 3, 8]).should == 4
|
35
|
+
average_bis([2, 3, 8]).should == 4
|
36
|
+
average_tris([2, 3, 8]).should == 4
|
37
|
+
average_quater([2, 3, 8]).should == 4
|
38
|
+
end
|
39
|
+
|
40
|
+
it "folds" do
|
41
|
+
foldl(->(n, a) { n/a }, 1.0, [1.0, 2.0, 3.0]).should == 1.0/1.0/2.0/3.0
|
42
|
+
foldr(->(n, a) { n/a }, 1.0, [1.0, 2.0, 3.0]).should == 1.0/3.0/2.0/1.0
|
43
|
+
end
|
44
|
+
|
45
|
+
it "mins and maxes" do
|
46
|
+
min([1, 2, 3]).should == 1
|
47
|
+
max([1, 2, 3]).should == 3
|
48
|
+
end
|
49
|
+
|
50
|
+
it "makes ranges" do
|
51
|
+
from_to(2, 3).should == (2..3)
|
52
|
+
from_one_to(3).should == (1..3)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "intersects arrays" do
|
56
|
+
intersect([[1, 2, 3], [2, 3, 4], [2, 3, 8]]).should == [2, 3]
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
data/functions.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'functions/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "functions"
|
8
|
+
gem.version = Functions::VERSION
|
9
|
+
gem.authors = ["Koen Handekyn"]
|
10
|
+
gem.email = ["koen.handekyn@up-nxt.com"]
|
11
|
+
gem.description = %q{functions programming in ruby}
|
12
|
+
gem.summary = %q{functions programming in ruby}
|
13
|
+
gem.homepage = "http://github.com"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
end
|
data/lib/functions.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
module Functions
|
2
|
+
|
3
|
+
module Prelude
|
4
|
+
|
5
|
+
Id = ->(x) { x }
|
6
|
+
|
7
|
+
Const = ->(c, x) { c }
|
8
|
+
|
9
|
+
Split_In = ->(n, xs) { xs.each_slice((xs.length+1)/n).to_a }
|
10
|
+
|
11
|
+
Split_In_Half = Split_In.curry.(2)
|
12
|
+
|
13
|
+
Merge_By = ->(f, xs, ys) do
|
14
|
+
|
15
|
+
return xs if ys.empty?
|
16
|
+
return ys if xs.empty?
|
17
|
+
|
18
|
+
x, *xt = xs
|
19
|
+
y, *yt = ys
|
20
|
+
|
21
|
+
return Merge_By.(f, xt, ys) >> x if f.nil? ? x <= y : f.(x) <= f.(y)
|
22
|
+
return Merge_By.(f, xs, yt) >> y
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
Merge = Merge_By.partial(nil)
|
27
|
+
|
28
|
+
Compose = ->(f, g, x) { f.(g.(x)) }.curry
|
29
|
+
|
30
|
+
# Manually curried version
|
31
|
+
# ComposeCurried = ->(f) { ->(g) { ->(x) { f.(g.(x)) } } }
|
32
|
+
|
33
|
+
After = ->(f, g, x) {
|
34
|
+
f = Par.(f) if Array === f;
|
35
|
+
g = Par.(g) if Array === g;
|
36
|
+
g.(f.(x))
|
37
|
+
}.curry
|
38
|
+
|
39
|
+
# Manually Curried Version
|
40
|
+
# AfterCurried = ->(f) { ->(g) { ->(x) {
|
41
|
+
# f = Par.(f) if Array === f;
|
42
|
+
# g = Par.(g) if Array === g;
|
43
|
+
# g.(f.(x))
|
44
|
+
# } } }
|
45
|
+
|
46
|
+
Send = ->(m, o) { o.send(m) }.curry
|
47
|
+
|
48
|
+
Flatten = Send.(:flatten)
|
49
|
+
# Flatten = ->(a) { a.flatten }
|
50
|
+
|
51
|
+
Reverse = Send.(:reverse)
|
52
|
+
# Reverse = ->(a) { a.reverse }
|
53
|
+
|
54
|
+
Length = Send.(:length)
|
55
|
+
# Length = ->(x) { x.length }
|
56
|
+
|
57
|
+
Foldl = ->(f, i, a) { a.inject(i) { |r, x| f.(r, x) } }.curry
|
58
|
+
|
59
|
+
ReduceLeft = ->(f, a) { a.inject { |r, x| f.(r, x) } }.curry
|
60
|
+
|
61
|
+
Foldr = ->(f, i, a) { Foldl.(f, i, a.reverse) }
|
62
|
+
|
63
|
+
ReduceRight = ->(f, a) { ReduceLeft.(f, a.reverse) }.curry
|
64
|
+
|
65
|
+
Zip = ->(a, b) { a.zip(b) }.curry
|
66
|
+
|
67
|
+
Map = ->(f, a) { a.map { |x| f.(x) } }.curry
|
68
|
+
|
69
|
+
Filter = ->(xs, f) { xs.select { |x| f.(x) } }.curry
|
70
|
+
|
71
|
+
Parallel = ->(f, g, x) { [f.(x), g.(x)] }.curry
|
72
|
+
|
73
|
+
Par = ->(fs, x) { fs.map { |f| f.(x) } }.curry
|
74
|
+
|
75
|
+
Intersect = ->(as) { as.inject(:&) }
|
76
|
+
|
77
|
+
FromTo = ->(from) { ->(to) { Range.new(from, to) } }
|
78
|
+
|
79
|
+
FromOneTo = FromTo.(1)
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# reference http://iain.nl/going-crazy-with-to_proc
|
2
|
+
|
3
|
+
class Array
|
4
|
+
# converts the array into a Proc where
|
5
|
+
# the first element is the method name, other elements are the values
|
6
|
+
def to_proc
|
7
|
+
head, *tail = *self
|
8
|
+
Proc.new { |obj, *other| obj.__send__(head, *(other + tail)) }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class Proc
|
13
|
+
# Composition of Procs (functions): (f+g)(x) = f(g(x))
|
14
|
+
def +(g)
|
15
|
+
# Prelude::Compose.(self,g)
|
16
|
+
->(x) { self.(g.(x)) }
|
17
|
+
end
|
18
|
+
# Composition of Procs (functions): (f<g)(x) = f(g(x))
|
19
|
+
def <(g)
|
20
|
+
# Prelude::Compose.(self,g)
|
21
|
+
->(x) { self.(g.(x)) }
|
22
|
+
end
|
23
|
+
# Composition of Procs (functions): (f>g)(x) = g(f(x))
|
24
|
+
def >(g)
|
25
|
+
# Prelude::After.(self,g)
|
26
|
+
->(x) { g.(self.(x)) }
|
27
|
+
end
|
28
|
+
# Partial evaluation of a Proc (function)
|
29
|
+
def partial(a)
|
30
|
+
self.curry.(a)
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Functions
|
2
|
+
|
3
|
+
module Prelude
|
4
|
+
|
5
|
+
Max = Send.(:max)
|
6
|
+
|
7
|
+
Min = Send.(:min)
|
8
|
+
|
9
|
+
Sum = ->(arr) { arr.inject(0, :+) }
|
10
|
+
|
11
|
+
Multiply = ->(arr) { arr.inject(1, :*) }
|
12
|
+
|
13
|
+
Divide = ->(arr) { arr.inject(:/) }
|
14
|
+
|
15
|
+
Average = Parallel.(Sum,Length) > Divide
|
16
|
+
|
17
|
+
IsDivisor = ->(a, c) { a % c == 0 }
|
18
|
+
|
19
|
+
Divisors = ->(a) { Filter.(FromOneTo.(a), IsDivisor.partial(a)) }
|
20
|
+
|
21
|
+
Gcd = ->(a, b) { b == 0 ? a : Gcd.(b, a % b) } # euclid algorithm
|
22
|
+
|
23
|
+
GcdA = ReduceLeft.(Gcd)
|
24
|
+
|
25
|
+
Lcm = ->(a, b) { a*b / Gcd.(a, b) } # mathematical law
|
26
|
+
|
27
|
+
LcmA = ReduceLeft.(Lcm)
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Functions
|
2
|
+
|
3
|
+
module Prelude
|
4
|
+
|
5
|
+
Merge_Sort_By = ->(f, xs) do
|
6
|
+
|
7
|
+
return xs if xs.length <= 1 # stopcondition
|
8
|
+
|
9
|
+
left, right = Split_In_Half.(xs)
|
10
|
+
Merge_By.(f, Merge_Sort_By.(f, left), Merge_Sort_By.(f, right))
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
Merge_Sort = Merge_Sort_By.partial(nil)
|
15
|
+
|
16
|
+
Quick_Sort_By = ->(f, list) do
|
17
|
+
return [] if list.size == 0
|
18
|
+
pivot, *xs = *list
|
19
|
+
smaller_than = f.nil? ? ->(y) { y < pivot } : ->(y) { f.(y) < f.(pivot) }
|
20
|
+
less, more = xs.partition &smaller_than
|
21
|
+
Quick_Sort_By.(f, less) + [pivot] + Quick_Sort_By.(f, more)
|
22
|
+
end
|
23
|
+
|
24
|
+
Quick_Sort = Quick_Sort_By.partial(nil)
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,306 @@
|
|
1
|
+
module Functions
|
2
|
+
|
3
|
+
module PreludeMeta
|
4
|
+
|
5
|
+
def self.included(klass)
|
6
|
+
klass.extend ClassMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
|
11
|
+
def create_proc_method(c, f, i=:f)
|
12
|
+
if Proc === f
|
13
|
+
define_method("#{c}_#{i}_proc", f)
|
14
|
+
return "#{c}_#{i}_proc"
|
15
|
+
else
|
16
|
+
return f
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def define_v1(c, definition)
|
21
|
+
key, value = definition[:as].first
|
22
|
+
self.send(key, c, *value)
|
23
|
+
end
|
24
|
+
|
25
|
+
def define_v2(definition, name)
|
26
|
+
key, value = definition
|
27
|
+
self.send(key, name, *value)
|
28
|
+
end
|
29
|
+
|
30
|
+
def define(*params)
|
31
|
+
if Symbol === params[0]
|
32
|
+
define_v1(*params)
|
33
|
+
else
|
34
|
+
name = params[0].delete(:as)
|
35
|
+
define_v2(*params[0], name)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def compose(c, f, g)
|
40
|
+
m = create_proc_method(c, f, :f)
|
41
|
+
n = create_proc_method(c, g, :g)
|
42
|
+
code = %Q{
|
43
|
+
def #{c}(x)
|
44
|
+
#{m}(#{n}(x))
|
45
|
+
end
|
46
|
+
}
|
47
|
+
module_eval(code)
|
48
|
+
end
|
49
|
+
|
50
|
+
alias :def_compose :compose
|
51
|
+
|
52
|
+
def after(c, f, g)
|
53
|
+
compose(c, g, f)
|
54
|
+
end
|
55
|
+
|
56
|
+
alias :def_after :after
|
57
|
+
|
58
|
+
def parallel(c, f, g)
|
59
|
+
m = create_proc_method(c, f, :f)
|
60
|
+
n = create_proc_method(c, g, :g)
|
61
|
+
code = %Q{
|
62
|
+
def #{c}(x)
|
63
|
+
[#{m}(x),#{n}(x)]
|
64
|
+
end
|
65
|
+
}
|
66
|
+
module_eval(code)
|
67
|
+
end
|
68
|
+
|
69
|
+
alias :def_parallel :parallel
|
70
|
+
|
71
|
+
def foldl(c, f, i)
|
72
|
+
m = create_proc_method(c, f)
|
73
|
+
code = %Q{
|
74
|
+
def #{c}(arr)
|
75
|
+
arr.inject(#{i}) { |r, x| #{m}(r,x) }
|
76
|
+
end
|
77
|
+
}
|
78
|
+
module_eval(code)
|
79
|
+
end
|
80
|
+
|
81
|
+
alias :def_foldl :foldl
|
82
|
+
|
83
|
+
def reduce_left(c, f)
|
84
|
+
m = create_proc_method(c, f)
|
85
|
+
code = %Q{
|
86
|
+
def #{c}(arr)
|
87
|
+
arr.inject { |r, x| #{m}(r,x) }
|
88
|
+
end
|
89
|
+
}
|
90
|
+
module_eval(code)
|
91
|
+
end
|
92
|
+
|
93
|
+
alias :def_reduce_left :reduce_left
|
94
|
+
|
95
|
+
def foldr(c, f, i)
|
96
|
+
m = create_proc_method(c, f)
|
97
|
+
code = %Q{
|
98
|
+
def #{c}(arr)
|
99
|
+
arr.reverse.inject(#{i}) { |r, x| #{m}(r,x) }
|
100
|
+
end
|
101
|
+
}
|
102
|
+
module_eval(code)
|
103
|
+
end
|
104
|
+
|
105
|
+
alias :def_foldr :foldr
|
106
|
+
|
107
|
+
def reduce_right(c, f)
|
108
|
+
m = create_proc_method(c, f)
|
109
|
+
code = %Q{
|
110
|
+
def #{c}(arr)
|
111
|
+
arr.reverse.inject { |r, x| #{m}(r,x) }
|
112
|
+
end
|
113
|
+
}
|
114
|
+
module_eval(code)
|
115
|
+
end
|
116
|
+
|
117
|
+
alias :def_reduce_right :reduce_right
|
118
|
+
|
119
|
+
def map(c, f)
|
120
|
+
m = create_proc_method(c, f)
|
121
|
+
code = %Q{
|
122
|
+
def #{c}(arr)
|
123
|
+
arr.map { |x| #{m}(x) }
|
124
|
+
end
|
125
|
+
}
|
126
|
+
module_eval(code)
|
127
|
+
end
|
128
|
+
|
129
|
+
alias :def_map :map
|
130
|
+
|
131
|
+
def filter(c, f)
|
132
|
+
m = create_proc_method(c, f)
|
133
|
+
code = %Q{
|
134
|
+
def #{c}(arr)
|
135
|
+
arr.select { |x| #{m}(x) }
|
136
|
+
end
|
137
|
+
}
|
138
|
+
module_eval(code)
|
139
|
+
end
|
140
|
+
|
141
|
+
alias :def_filter :filter
|
142
|
+
|
143
|
+
def method(m)
|
144
|
+
code = %Q{
|
145
|
+
def #{m}(o)
|
146
|
+
o.#{m}
|
147
|
+
end
|
148
|
+
}
|
149
|
+
module_eval(code)
|
150
|
+
end
|
151
|
+
|
152
|
+
alias :def_method :method
|
153
|
+
|
154
|
+
end
|
155
|
+
|
156
|
+
def m(method)
|
157
|
+
lambda(&method(method))
|
158
|
+
end
|
159
|
+
|
160
|
+
def f(f)
|
161
|
+
Symbol === f ? f = m(f) : f
|
162
|
+
end
|
163
|
+
|
164
|
+
def id(x)
|
165
|
+
x
|
166
|
+
end
|
167
|
+
|
168
|
+
def const(c, x)
|
169
|
+
c
|
170
|
+
end
|
171
|
+
|
172
|
+
def split_in(xs, n)
|
173
|
+
xs.each_slice((xs.length+1)/n).to_a
|
174
|
+
end
|
175
|
+
|
176
|
+
def split_in_half(xs)
|
177
|
+
split_in(xs, 2)
|
178
|
+
end
|
179
|
+
|
180
|
+
def merge(xs, ys, &by)
|
181
|
+
|
182
|
+
return xs if ys.empty?
|
183
|
+
return ys if xs.empty?
|
184
|
+
|
185
|
+
x, *xt = xs
|
186
|
+
y, *yt = ys
|
187
|
+
|
188
|
+
return merge(xt, ys, &by) >> x if block_given? ? by.(x) <= by.(y) : x <= y
|
189
|
+
return merge(xs, yt, &by) >> y
|
190
|
+
|
191
|
+
end
|
192
|
+
|
193
|
+
def merge_sort(xs, &by)
|
194
|
+
return xs if xs.length <= 1 # stopcondition
|
195
|
+
left, right = split_in_half(xs)
|
196
|
+
merge(merge_sort(left, &by), merge_sort(right, &by), &by)
|
197
|
+
end
|
198
|
+
|
199
|
+
def quick_sort(list)
|
200
|
+
return [] if list.size == 0
|
201
|
+
pivot, *xs = *list
|
202
|
+
less, more = xs.partition { |y| y < pivot }
|
203
|
+
quick_sort(less) + [pivot] + quick_sort(more)
|
204
|
+
end
|
205
|
+
|
206
|
+
def compose(f, g, x)
|
207
|
+
f = f(f)
|
208
|
+
g = f(g)
|
209
|
+
f.(g.(x))
|
210
|
+
end
|
211
|
+
|
212
|
+
def after(f, g, x)
|
213
|
+
f = f(f)
|
214
|
+
g = f(g)
|
215
|
+
return g.(par(*f, x)) if Array === f && Proc === g
|
216
|
+
return par(*g, f.(x)) if Proc === f && Array === g
|
217
|
+
return par(*g, par(*f, x)) if Array === f && Array === g
|
218
|
+
return g.(f.(x)) # else
|
219
|
+
end
|
220
|
+
|
221
|
+
extend ClassMethods
|
222
|
+
|
223
|
+
def_method :flatten
|
224
|
+
|
225
|
+
#def flatten(a)
|
226
|
+
# a.flatten
|
227
|
+
#end
|
228
|
+
|
229
|
+
def_method :length
|
230
|
+
|
231
|
+
#def length(a)
|
232
|
+
# a.length
|
233
|
+
#end
|
234
|
+
|
235
|
+
def_method :reverse
|
236
|
+
|
237
|
+
#def reverse(a)
|
238
|
+
# a.reverse
|
239
|
+
#end
|
240
|
+
|
241
|
+
def foldl(f, i, a)
|
242
|
+
a.inject(i) { |r, x| f(f).(r, x) }
|
243
|
+
end
|
244
|
+
|
245
|
+
def foldr(f, i, a)
|
246
|
+
foldl(f(f), i, a.reverse)
|
247
|
+
end
|
248
|
+
|
249
|
+
def zip(a, b)
|
250
|
+
a.zip(b)
|
251
|
+
end
|
252
|
+
|
253
|
+
def map(a, f)
|
254
|
+
a.map { |x| f(f).(x) }
|
255
|
+
end
|
256
|
+
|
257
|
+
def filter(a, f)
|
258
|
+
a.select { |x| f(f).(x) }
|
259
|
+
end
|
260
|
+
|
261
|
+
def sum(a)
|
262
|
+
a.inject(0, :+)
|
263
|
+
end
|
264
|
+
|
265
|
+
def parallel(f, g, x)
|
266
|
+
[f(f).(x), f(g).(x)]
|
267
|
+
end
|
268
|
+
|
269
|
+
def par(*fs, x)
|
270
|
+
fs.map { |f| f(f).(x) }
|
271
|
+
end
|
272
|
+
|
273
|
+
def_method :even?
|
274
|
+
|
275
|
+
def_method :odd?
|
276
|
+
|
277
|
+
def divide(arr)
|
278
|
+
arr.inject { |a,b| a/b }
|
279
|
+
end
|
280
|
+
|
281
|
+
define :sum_length, as: { parallel: [:sum, :length] }
|
282
|
+
|
283
|
+
define :average, as: { :after => [ :sum_length, :divide ] }
|
284
|
+
|
285
|
+
# TODO write with operator :& ?
|
286
|
+
# def_reduce_left :intersect, ->(a,b) { a&b } # short
|
287
|
+
# reduce_left :intersect, ->(a,b) { a&b } # longer
|
288
|
+
define :intersect, as: {reduce_left: ->(a, b) { a&b }} # longest
|
289
|
+
|
290
|
+
def_method :min
|
291
|
+
|
292
|
+
def_method :max
|
293
|
+
|
294
|
+
def from_to(from, to)
|
295
|
+
Range.new(from, to)
|
296
|
+
end
|
297
|
+
|
298
|
+
def from_one_to(to)
|
299
|
+
Range.new(1, to)
|
300
|
+
end
|
301
|
+
|
302
|
+
end
|
303
|
+
|
304
|
+
end
|
305
|
+
|
306
|
+
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require_relative '../examples/prelude_usage'
|
2
|
+
require_relative '../examples/prelude_meta_usage'
|
3
|
+
|
4
|
+
include PreludeUsage
|
5
|
+
include PreludeUsageWithDefs
|
6
|
+
|
7
|
+
require 'benchmark'
|
8
|
+
|
9
|
+
[10, 100, 1000, 10000].each do |n|
|
10
|
+
Benchmark.bm(40) do |b|
|
11
|
+
b.report("Sum_Of_Squares(n=#{n}): ") { (100000/n).times { Sum_Of_Squares.((1..n).to_a) } }
|
12
|
+
b.report("sum_of_squares(n=#{n}): ") { (100000/n).times { sum_of_squares ((1..n).to_a) } }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
[10, 100, 1000, 10000].each do |n|
|
17
|
+
Benchmark.bm(40) do |b|
|
18
|
+
b.report("Average(n=#{n}): ") { (100000/n).times { Average.((1..n).to_a) } }
|
19
|
+
b.report("average(n=#{n}): ") { (100000/n).times { average ((1..n).to_a) } }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
[10, 100, 1000, 10000].each do |n|
|
24
|
+
Benchmark.bm(40) do |b|
|
25
|
+
b.report("Sum.(n=#{n}): ") { (100000/n).times { Sum.((1..n).to_a) } }
|
26
|
+
b.report("sum(n=#{n}): ") { (100000/n).times { sum((1..n).to_a) } }
|
27
|
+
b.report("sum_bis(n=#{n}): ") { (100000/n).times { sum_bis((1..n).to_a) } }
|
28
|
+
b.report("sum_tris(n=#{n}): ") { (100000/n).times { sum_tris((1..n).to_a) } }
|
29
|
+
b.report("sum_quater(n=#{n}): ") { (100000/n).times { sum_quater((1..n).to_a) } }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
[10, 100, 1000].each do |n|
|
34
|
+
random_array = (0..n).to_a.shuffle
|
35
|
+
Benchmark.bm(40) do |b|
|
36
|
+
b.report("lambda/merge_sort(n=#{n}): ") { (100000/n).times { Merge_Sort.(random_array) } }
|
37
|
+
b.report("def/merge_sort(n=#{n}): ") { (100000/n).times { merge_sort(random_array) } }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
[10, 100, 1000].each do |n|
|
42
|
+
random_array = (0..n).to_a.shuffle
|
43
|
+
Benchmark.bm(40) do |b|
|
44
|
+
b.report("lambda/quick_sort(n=#{n}): ") { (100000/n).times { Quick_Sort.(random_array) } }
|
45
|
+
# b.report("lambda/quick_sort/nil(n=#{n}): ") { (100000/n).times { Quick_Sort_By.(nil, random_array) } } # the same by definition
|
46
|
+
b.report("lambda/quick_sort/identity(n=#{n}): ") { (100000/n).times { Quick_Sort_By.(Id, random_array) } }
|
47
|
+
b.report("def/quick_sort(n=#{n}): ") { (100000/n).times { quick_sort(random_array) } }
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'functions'
|
2
|
+
|
3
|
+
include Functions::Prelude
|
4
|
+
|
5
|
+
describe Functions::Prelude, "math" do
|
6
|
+
|
7
|
+
it "divides" do
|
8
|
+
Divide.([9,2]).should eq(9/2)
|
9
|
+
Divide.([8,2,2]).should eq(8/2/2)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "knows about divisors" do
|
13
|
+
IsDivisor.(8,2).should eq(true)
|
14
|
+
IsDivisor.(8,3).should eq(false)
|
15
|
+
Divisors.(12).sort.should eq([1,2,3,4,6,12])
|
16
|
+
end
|
17
|
+
|
18
|
+
it "knows about range building" do
|
19
|
+
FromOneTo.(3).should eq(1..3)
|
20
|
+
FromOneTo.(3).to_a.should eq([1,2,3])
|
21
|
+
FromTo.(2).(8).to_a.should eq([2,3,4,5,6,7,8])
|
22
|
+
end
|
23
|
+
|
24
|
+
it "knows about gcd" do
|
25
|
+
Gcd.(12,9).should eq(3)
|
26
|
+
Gcd.(4,8).should eq(4)
|
27
|
+
GcdA.([12,9,6]).should eq(3)
|
28
|
+
GcdA.([4,8,2]).should eq(2)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "knows about lcm" do
|
32
|
+
Lcm.(12,9).should eq(36)
|
33
|
+
Lcm.(6,8).should eq(24)
|
34
|
+
LcmA.([12,9]).should eq(36)
|
35
|
+
LcmA.([12,9,2]).should eq(36)
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'functions'
|
2
|
+
|
3
|
+
include Functions::Prelude
|
4
|
+
|
5
|
+
describe Functions::Prelude, "basic" do
|
6
|
+
|
7
|
+
Power = ->(p, x) { x**p }.curry
|
8
|
+
Square = Power.(2)
|
9
|
+
Squares = Map.(Square)
|
10
|
+
|
11
|
+
it "composes" do
|
12
|
+
sum_of_squares = Compose.(Sum).(Squares)
|
13
|
+
sum_of_squares.([2, 3, 4]).should eq(4+9+16)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "has a compose operator" do
|
17
|
+
sum_of_squares = Sum < Squares
|
18
|
+
sum_of_squares.([2, 3, 4]).should eq(4+9+16)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "folds" do
|
22
|
+
inc_with = ->(f, n, m) { n + f.(m) }.curry
|
23
|
+
sum_of = ->(f, arr) { Foldl.(inc_with.(f), 0, arr) }.curry
|
24
|
+
sum_of.(Square).([1,2,3]).should eq(1+4+9)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "composes using after with implicit parallel" do
|
28
|
+
average = After.([Sum, Length]).(Divide)
|
29
|
+
average.([2, 3, 8]).should eq((2+3+8)/3)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "mixes parallel with after operator" do
|
33
|
+
average = Parallel.(Sum, Length) > Divide
|
34
|
+
average.([2, 3, 8]).should eq((2+3+8)/3)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "mixes par with after operator" do
|
38
|
+
average = Par.([Sum, Length]) > Divide
|
39
|
+
average.([2, 3, 8]).should eq((2+3+8)/3)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "flattens arrays" do
|
43
|
+
Flatten.([[1, 2, 3], [2, 3]]).should eq([1,2,3,2,3])
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'functions'
|
2
|
+
|
3
|
+
include Functions::PreludeMeta
|
4
|
+
|
5
|
+
describe Functions::PreludeMeta, "basic meta prelude usage" do
|
6
|
+
|
7
|
+
it "sums" do
|
8
|
+
sum([1, 2, 3]).should == 1+2+3
|
9
|
+
end
|
10
|
+
|
11
|
+
it "takes averages" do
|
12
|
+
average([2, 3, 8]).should == 4
|
13
|
+
end
|
14
|
+
|
15
|
+
it "folds" do
|
16
|
+
foldl(->(n, a) { n/a }, 1.0, [1.0, 2.0, 3.0]).should == 1.0/1.0/2.0/3.0
|
17
|
+
foldr(->(n, a) { n/a }, 1.0, [1.0, 2.0, 3.0]).should == 1.0/3.0/2.0/1.0
|
18
|
+
end
|
19
|
+
|
20
|
+
it "mins and maxes" do
|
21
|
+
min([1, 2, 3]).should == 1
|
22
|
+
max([1, 2, 3]).should == 3
|
23
|
+
end
|
24
|
+
|
25
|
+
it "makes ranges" do
|
26
|
+
from_to(2, 3).should == (2..3)
|
27
|
+
from_one_to(3).should == (1..3)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "intersects arrays" do
|
31
|
+
intersect([[1, 2, 3], [2, 3, 4], [2, 3, 8]]).should == [2, 3]
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
4
|
+
# loaded once.
|
5
|
+
#
|
6
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
7
|
+
RSpec.configure do |config|
|
8
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
9
|
+
config.run_all_when_everything_filtered = true
|
10
|
+
config.filter_run :focus
|
11
|
+
|
12
|
+
# Run specs in random order to surface order dependencies. If you find an
|
13
|
+
# order dependency and want to debug it, you can fix the order by providing
|
14
|
+
# the seed, which is printed after each run.
|
15
|
+
# --seed 1234
|
16
|
+
config.order = 'random'
|
17
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'examples/prelude_lambda'
|
2
|
+
require 'examples/prelude_meta'
|
3
|
+
|
4
|
+
#require 'test/unit'
|
5
|
+
require 'minitest/autorun'
|
6
|
+
require 'minitest/benchmark'
|
7
|
+
|
8
|
+
#require "minitest/reporters"
|
9
|
+
# MiniTest::Reporters.use! # add this to your run configuration
|
10
|
+
|
11
|
+
include PreludeLambdaUsage
|
12
|
+
include PreludeMetaUsage
|
13
|
+
|
14
|
+
class TestPrelude < MiniTest::Unit::TestCase
|
15
|
+
|
16
|
+
include Functions::Prelude
|
17
|
+
|
18
|
+
def test_sum_of_squares
|
19
|
+
assert_performance_linear 0.99 do |n| # n is a range value
|
20
|
+
100.times { Sum_Of_Squares.((1..n).to_a) }
|
21
|
+
end
|
22
|
+
assert_performance_linear 0.99 do |n| # n is a range value
|
23
|
+
100.times { sum_of_squares((1..n).to_a) }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_average
|
28
|
+
assert_performance_linear 0.99 do |n| # n is a range value
|
29
|
+
100.times { Average.((1..n).to_a) }
|
30
|
+
end
|
31
|
+
assert_performance_linear 0.99 do |n| # n is a range value
|
32
|
+
100.times { average((1..n).to_a) }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
metadata
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: functions
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Koen Handekyn
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-04-10 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: functions programming in ruby
|
15
|
+
email:
|
16
|
+
- koen.handekyn@up-nxt.com
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- .gitignore
|
22
|
+
- .rspec
|
23
|
+
- Gemfile
|
24
|
+
- LICENSE.txt
|
25
|
+
- README.md
|
26
|
+
- Rakefile
|
27
|
+
- examples/prelude_lambda.rb
|
28
|
+
- examples/prelude_meta.rb
|
29
|
+
- examples/spec/prelude_lambda_spec.rb
|
30
|
+
- examples/spec/prelude_meta_spec.rb
|
31
|
+
- functions.gemspec
|
32
|
+
- lib/functions.rb
|
33
|
+
- lib/functions/prelude_lambda.rb
|
34
|
+
- lib/functions/prelude_lambda/basic.rb
|
35
|
+
- lib/functions/prelude_lambda/ext.rb
|
36
|
+
- lib/functions/prelude_lambda/math.rb
|
37
|
+
- lib/functions/prelude_lambda/sorting.rb
|
38
|
+
- lib/functions/prelude_meta.rb
|
39
|
+
- lib/functions/shared/ext.rb
|
40
|
+
- lib/functions/version.rb
|
41
|
+
- performance/prelude_performance.rb
|
42
|
+
- spec/prelude_lambda_math_spec.rb
|
43
|
+
- spec/prelude_lambda_spec.rb
|
44
|
+
- spec/prelude_meta_spec.rb
|
45
|
+
- spec/spec_helper.rb
|
46
|
+
- test/test_prelude_performance.rb
|
47
|
+
homepage: http://github.com
|
48
|
+
licenses: []
|
49
|
+
post_install_message:
|
50
|
+
rdoc_options: []
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ! '>='
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: '0'
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
61
|
+
requirements:
|
62
|
+
- - ! '>='
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0'
|
65
|
+
requirements: []
|
66
|
+
rubyforge_project:
|
67
|
+
rubygems_version: 1.8.24
|
68
|
+
signing_key:
|
69
|
+
specification_version: 3
|
70
|
+
summary: functions programming in ruby
|
71
|
+
test_files:
|
72
|
+
- spec/prelude_lambda_math_spec.rb
|
73
|
+
- spec/prelude_lambda_spec.rb
|
74
|
+
- spec/prelude_meta_spec.rb
|
75
|
+
- spec/spec_helper.rb
|
76
|
+
- test/test_prelude_performance.rb
|