functions 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ Yjc3YjRkZDYwYmMzZjZmYmUwMzVjMTVkZGQxYWJkMThlZWEyZWJiMg==
5
+ data.tar.gz: !binary |-
6
+ Y2ZmYjg4OGJiNTg1ZmQxY2M1MjMxNmZmMzZjNWE2ODU5NWY1YzljOA==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ NGRmMWYxMmY1ZTU0OWY1ZTM0ODk5ZmJhNTZkNjQwYmJmNWU3NmExZmViYWM3
10
+ NzQxOTYwMzliNTRhMDczNDE5OTRhZmYzYWE0MjhhNjZkODYyOTBiYTlkM2Y3
11
+ YzQwMmM2YjkxZTZkMjczNWM5YWVjNGQ0NmM2ODRmZjhiZjgxN2Q=
12
+ data.tar.gz: !binary |-
13
+ MDNmNDYxZDRlMDMzN2ZkM2U0ODY3MTkyZGMzN2JhMDAyMzA0ZGFkMmJiZWVi
14
+ NGRmYzFkZGY3OWI1ZjAzZjJiZDk0NmQ2M2JkZDI1ZjRjNWQyM2U4YTdmOGZj
15
+ ZjM5Nzg2NzlhZTVlYTNlMTMzOGFjYThjZTdkYzRkMTcxNmZiNDQ=
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Functional
2
2
 
3
3
  This library facilitates writing code in a more functional style inside Ruby.
4
+ How this is fun.
4
5
 
5
6
  ## Installation
6
7
 
@@ -39,10 +40,10 @@ The lambda style allows you to write functions like this
39
40
 
40
41
  Average = After.( [Sum,Length] ).( Divide )
41
42
 
42
- Gcd = ->(a,b) { (Divisors.(a) & Divisors.(b)).max }
43
+ Gcd = ->(a,b) { (Divisors.(a) & Divisors.(b)).max } # literal translation of the definition, just as an example
43
44
 
44
45
  # Gcd of an array
45
- GcdA1 = Max < Intersect < Map.(Divisors) # litteral translation of the definition
46
+ GcdA1 = Max < Intersect < Map.(Divisors) # literal translation of the definition
46
47
  GcdA2 = ReduceLeft.(Gcd) # faster
47
48
 
48
49
  # Lcm of an array in function of Lcm of a pair
@@ -76,6 +77,13 @@ The meta style allows you to write functions like this
76
77
 
77
78
  end
78
79
 
80
+ ## License
81
+
82
+ This code is currently copyrighted under the AGPL license.
83
+ See <http://www.gnu.org/licenses/agpl.html> for more information.
84
+
85
+ ![AGPL license](http://www.gnu.org/graphics/agplv3-155x51.png)
86
+
79
87
  ## Contributing
80
88
 
81
89
  1. Fork it
@@ -4,69 +4,55 @@ module PreludeMetaUsage
4
4
 
5
5
  include Functions::PreludeMeta
6
6
 
7
- def power(x, p)
8
- x ** p
9
- end
7
+ # returns x to the power of p
8
+ def power(x, p) x ** p end
10
9
 
11
- def square(x)
12
- power(x, 2)
13
- end
10
+ # returns x^2
11
+ def square(x) power(x, 2) end
14
12
 
15
- def_map :squares, :square
13
+ # returns the list of the squares
14
+ def squares(a) map(a, :square) end
16
15
 
17
- def squares_bis(a)
18
- map(a, :square)
19
- end
16
+ define :squares_bis, as: { map: :square }
20
17
 
21
- def_map :squares_tris, ->(x) { x**2 }
18
+ # test
19
+ # def_map :squares, :square
20
+ # def_map :squares_tris, ->(x) { x**2 }
21
+ # define :squares, as: { map: ->(x) { x**2 } }
22
22
 
23
- define :squares_quater, as: { map: ->(x) { x**2 } }
23
+ # returns all elements of an enumerable that are even
24
+ define :evens, as: { filter: :even? }
24
25
 
25
- define :squares_quinquies, as: { map: :square }
26
+ # def_filter :evens, :even?
26
27
 
27
- def_filter :evens, :even?
28
-
29
- # same as above
30
28
  # filter :evens, :even?
31
29
 
32
- def_filter :odds, ->(x) { ! x.even? }
30
+ define :odds, as: { filter: :odd? }
33
31
 
34
- define :evens_bis, as: { filter: :even? }
32
+ # def_filter :odds, ->(x) { ! x.even? }
35
33
 
36
- def_compose :sum_of_squares, :sum, :squares
34
+ def sum_of_squares(a) compose(:sum, :squares, a) end
37
35
 
38
- def sum_of_squares_bis(a)
39
- compose(:sum, :squares, a)
40
- end
36
+ define :sum_of_squares_bis, as: { compose: [:sum, :squares] }
41
37
 
42
- define :sum_of_squares_tris, as: { compose: [:sum, :squares] }
38
+ # compose :sum_of_squares, :sum, :squares
43
39
 
44
- def average_bis(a)
45
- after([:sum, :length], :divide, a)
46
- end
40
+ def average_bis(a) after([:sum, :length], :divide, a) end
47
41
 
48
42
  define :average_tris, as: { :after => [ :sum_length, :divide ] }
49
43
 
50
- def_after :average_quater, :sum_length, :divide
44
+ # after :average_quater, :sum_length, :divide
51
45
 
52
- def inc_with(f, n, m)
53
- m + f(f).(n)
54
- end
46
+ def inc_with(f, n, m) m + f(f).(n) end
55
47
 
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
48
+ def sum_of(f, a) a.inject(0) { |r, x| r + f(f).(x) } end
61
49
 
62
- def add(a,b)
63
- a+b
64
- end
50
+ def add(a,b) a+b end
65
51
 
66
- def_foldl :sum_bis, :add, 0
52
+ define :sum_bis, as: { foldl: [:add, 0]}
67
53
 
68
- define :sum_tris, as: { foldl: [:add, 0]}
54
+ # foldl :sum_bis, :add, 0
69
55
 
70
- define foldl: [:add, 0], as: :sum_quater
56
+ # define foldl: [:add, 0], as: :sum_quater
71
57
 
72
58
  end
@@ -7,53 +7,27 @@ describe PreludeMetaUsage, "basic meta prelude usage" do
7
7
  it "squares" do
8
8
  squares([1, 2, 3]).should == [1, 4, 9]
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
10
  end
14
11
 
15
12
  it "evens and odds" do
16
13
  evens([1, 2, 3, 4, 5]).should == [2, 4]
17
- evens_bis([1, 2, 3, 4, 5]).should == [2, 4]
18
14
  odds([1, 2, 3, 4, 5]).should == [1, 3, 5]
19
15
  end
20
16
 
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
17
+ it "takes sums of squares" do
25
18
  sum_of(:square, [2, 3, 1]).should == 2*2+3*3+1*1
26
19
  sum_of(->(x) { x*x }, [2, 3, 1]).should == 2*2+3*3+1*1
27
- sum([1, 2, 3]).should == 1+2+3
20
+ sum_of_squares([2, 3, 4]).should == 2*2+3*3+4*4
21
+ sum_of_squares_bis([2, 3, 4]).should == 2*2+3*3+4*4
22
+ end
23
+
24
+ it "takes sums by some variant definitions" do
28
25
  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
26
  end
32
27
 
33
- it "takes averages" do
34
- average([2, 3, 8]).should == 4
28
+ it "takes averages by some variant definitions" do
35
29
  average_bis([2, 3, 8]).should == 4
36
30
  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
31
  end
58
32
 
59
33
  end
@@ -2,14 +2,20 @@ module Functions
2
2
 
3
3
  module Prelude
4
4
 
5
+ # the identity function
5
6
  Id = ->(x) { x }
6
7
 
8
+ # the constant function
7
9
  Const = ->(c, x) { c }
8
10
 
11
+ # splits a list xs in peices of size n
9
12
  Split_In = ->(n, xs) { xs.each_slice((xs.length+1)/n).to_a }
10
13
 
14
+ # splits a list in half
11
15
  Split_In_Half = Split_In.curry.(2)
12
16
 
17
+ # merges two lists by a function f that compares the values
18
+ # if no function is given the values are compared by the "<" operator
13
19
  Merge_By = ->(f, xs, ys) do
14
20
 
15
21
  return xs if ys.empty?
@@ -23,37 +29,49 @@ module Functions
23
29
 
24
30
  end
25
31
 
32
+ # merges two list by the natural comparison operator <
26
33
  Merge = Merge_By.partial(nil)
27
34
 
35
+ # composes two functions
28
36
  Compose = ->(f, g, x) { f.(g.(x)) }.curry
29
37
 
30
- # Manually curried version
31
- # ComposeCurried = ->(f) { ->(g) { ->(x) { f.(g.(x)) } } }
38
+ # manually curried version of the Compose function
39
+ ComposeCurried = ->(f) { ->(g) { ->(x) { f.(g.(x)) } } }
32
40
 
41
+ # composes two functions in reverse sequence
33
42
  After = ->(f, g, x) {
34
43
  f = Par.(f) if Array === f;
35
44
  g = Par.(g) if Array === g;
36
45
  g.(f.(x))
37
46
  }.curry
38
47
 
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
- # } } }
48
+ # manually curried Version of the After composition function
49
+ AfterCurried = ->(f) { ->(g) { ->(x) {
50
+ f = Par.(f) if Array === f;
51
+ g = Par.(g) if Array === g;
52
+ g.(f.(x))
53
+ } } }
45
54
 
55
+ # sends the message m to an object o
56
+ #
57
+ # @param [Symbol] the method to be called on the object o
58
+ # @return the result of calling the message m on the object o
46
59
  Send = ->(m, o) { o.send(m) }.curry
47
60
 
61
+ # Flattens an array
62
+ #
63
+ # @param [#flatten] the array to flatten
48
64
  Flatten = Send.(:flatten)
49
- # Flatten = ->(a) { a.flatten }
50
65
 
66
+ # Reverses an array
67
+ #
68
+ # @param [#reverse] the array to reverse
51
69
  Reverse = Send.(:reverse)
52
- # Reverse = ->(a) { a.reverse }
53
70
 
71
+ # Returns the length
54
72
  Length = Send.(:length)
55
- # Length = ->(x) { x.length }
56
73
 
74
+ #
57
75
  Foldl = ->(f, i, a) { a.inject(i) { |r, x| f.(r, x) } }.curry
58
76
 
59
77
  ReduceLeft = ->(f, a) { a.inject { |r, x| f.(r, x) } }.curry
@@ -66,7 +84,7 @@ module Functions
66
84
 
67
85
  Map = ->(f, a) { a.map { |x| f.(x) } }.curry
68
86
 
69
- Filter = ->(xs, f) { xs.select { |x| f.(x) } }.curry
87
+ Filter = ->(f, xs) { xs.select { |x| f.(x) } }.curry
70
88
 
71
89
  Parallel = ->(f, g, x) { [f.(x), g.(x)] }.curry
72
90
 
@@ -10,6 +10,9 @@ class Array
10
10
  end
11
11
 
12
12
  class Proc
13
+ def self.compose(f, g)
14
+ ->(*args) { g[f[*args]] }
15
+ end
13
16
  # Composition of Procs (functions): (f+g)(x) = f(g(x))
14
17
  def +(g)
15
18
  # Prelude::Compose.(self,g)
@@ -29,4 +32,4 @@ class Proc
29
32
  def partial(a)
30
33
  self.curry.(a)
31
34
  end
32
- end
35
+ end
@@ -16,7 +16,7 @@ module Functions
16
16
 
17
17
  IsDivisor = ->(a, c) { a % c == 0 }
18
18
 
19
- Divisors = ->(a) { Filter.(FromOneTo.(a), IsDivisor.partial(a)) }
19
+ Divisors = ->(a) { Filter.(IsDivisor.partial(a), FromOneTo.(a)) }
20
20
 
21
21
  Gcd = ->(a, b) { b == 0 ? a : Gcd.(b, a % b) } # euclid algorithm
22
22
 
@@ -15,6 +15,7 @@ module Functions
15
15
 
16
16
  Quick_Sort_By = ->(f, list) do
17
17
  return [] if list.size == 0
18
+ return list if list.size == 1
18
19
  pivot, *xs = *list
19
20
  smaller_than = f.nil? ? ->(y) { y < pivot } : ->(y) { f.(y) < f.(pivot) }
20
21
  less, more = xs.partition &smaller_than
@@ -47,13 +47,13 @@ module Functions
47
47
  module_eval(code)
48
48
  end
49
49
 
50
- alias :def_compose :compose
50
+ #alias :def_compose :compose
51
51
 
52
52
  def after(c, f, g)
53
53
  compose(c, g, f)
54
54
  end
55
55
 
56
- alias :def_after :after
56
+ #alias :def_after :after
57
57
 
58
58
  def parallel(c, f, g)
59
59
  m = create_proc_method(c, f, :f)
@@ -66,7 +66,7 @@ module Functions
66
66
  module_eval(code)
67
67
  end
68
68
 
69
- alias :def_parallel :parallel
69
+ #alias :def_parallel :parallel
70
70
 
71
71
  def foldl(c, f, i)
72
72
  m = create_proc_method(c, f)
@@ -78,7 +78,7 @@ module Functions
78
78
  module_eval(code)
79
79
  end
80
80
 
81
- alias :def_foldl :foldl
81
+ #alias :def_foldl :foldl
82
82
 
83
83
  def reduce_left(c, f)
84
84
  m = create_proc_method(c, f)
@@ -90,7 +90,7 @@ module Functions
90
90
  module_eval(code)
91
91
  end
92
92
 
93
- alias :def_reduce_left :reduce_left
93
+ #alias :def_reduce_left :reduce_left
94
94
 
95
95
  def foldr(c, f, i)
96
96
  m = create_proc_method(c, f)
@@ -102,7 +102,7 @@ module Functions
102
102
  module_eval(code)
103
103
  end
104
104
 
105
- alias :def_foldr :foldr
105
+ #alias :def_foldr :foldr
106
106
 
107
107
  def reduce_right(c, f)
108
108
  m = create_proc_method(c, f)
@@ -114,7 +114,7 @@ module Functions
114
114
  module_eval(code)
115
115
  end
116
116
 
117
- alias :def_reduce_right :reduce_right
117
+ #alias :def_reduce_right :reduce_right
118
118
 
119
119
  def map(c, f)
120
120
  m = create_proc_method(c, f)
@@ -126,7 +126,7 @@ module Functions
126
126
  module_eval(code)
127
127
  end
128
128
 
129
- alias :def_map :map
129
+ #alias :def_map :map
130
130
 
131
131
  def filter(c, f)
132
132
  m = create_proc_method(c, f)
@@ -138,7 +138,7 @@ module Functions
138
138
  module_eval(code)
139
139
  end
140
140
 
141
- alias :def_filter :filter
141
+ #alias :def_filter :filter
142
142
 
143
143
  def method(m)
144
144
  code = %Q{
@@ -222,21 +222,21 @@ module Functions
222
222
 
223
223
  def_method :flatten
224
224
 
225
- #def flatten(a)
226
- # a.flatten
227
- #end
228
-
225
+ # @return calls the length method on the object
229
226
  def_method :length
230
227
 
231
- #def length(a)
232
- # a.length
233
- #end
234
-
228
+ # @param object the target object
229
+ # @return calls the reverse method on the object
235
230
  def_method :reverse
236
231
 
237
- #def reverse(a)
238
- # a.reverse
239
- #end
232
+ # @param object [#min] the object to call the min method on
233
+ # @return calls the min method on the Enumerable
234
+ def_method :min
235
+
236
+ # @param [#max] the object to call the max method on
237
+ # @return [Integer] the maximum
238
+ def_method :max
239
+
240
240
 
241
241
  def foldl(f, i, a)
242
242
  a.inject(i) { |r, x| f(f).(r, x) }
@@ -280,15 +280,12 @@ module Functions
280
280
 
281
281
  define :average, as: { :after => [ :sum_length, :divide ] }
282
282
 
283
- # TODO write with operator :& ?
284
- # def_reduce_left :intersect, ->(a,b) { a&b } # short
285
- # reduce_left :intersect, ->(a,b) { a&b } # longer
286
283
  define :intersect, as: {reduce_left: ->(a, b) { a&b }} # longest
287
284
 
288
- def_method :min
289
-
290
- def_method :max
291
-
285
+ # creates a range
286
+ #
287
+ # param from [Fixnum] the start of the range
288
+ # param to [Fixnum] the end of the range
292
289
  def from_to(from, to)
293
290
  Range.new(from, to)
294
291
  end
@@ -3,4 +3,15 @@ class Array
3
3
  def >> a
4
4
  self.unshift a
5
5
  end
6
+ end
7
+
8
+ module Kernel
9
+
10
+ def tailrecurse(&b)
11
+ result = []
12
+ loop do
13
+ result = b.(*result)
14
+ end
15
+ end
16
+
6
17
  end
@@ -1,3 +1,3 @@
1
1
  module Functions
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
@@ -43,4 +43,10 @@ describe Functions::Prelude, "basic" do
43
43
  Flatten.([[1, 2, 3], [2, 3]]).should eq([1,2,3,2,3])
44
44
  end
45
45
 
46
+ it "sorts arrays" do
47
+ Quick_Sort.([3,3,5,6,7,1,2]).should == [1,2,3,3,5,6,7]
48
+ Quick_Sort.([1,1,1,1,1,1,1]).should == [1,1,1,1,1,1,1]
49
+ Merge_Sort.([3,3,5,6,7,1,2]).should == [1,2,3,3,5,6,7]
50
+ end
51
+
46
52
  end
metadata CHANGED
@@ -1,15 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: functions
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
5
- prerelease:
4
+ version: 0.0.4
6
5
  platform: ruby
7
6
  authors:
8
7
  - Koen Handekyn
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-04-10 00:00:00.000000000 Z
11
+ date: 2013-10-17 00:00:00.000000000 Z
13
12
  dependencies: []
14
13
  description: functional programming in ruby
15
14
  email:
@@ -46,27 +45,26 @@ files:
46
45
  - test/test_prelude_performance.rb
47
46
  homepage: https://github.com/koenhandekyn/functions
48
47
  licenses: []
48
+ metadata: {}
49
49
  post_install_message:
50
50
  rdoc_options: []
51
51
  require_paths:
52
52
  - lib
53
53
  required_ruby_version: !ruby/object:Gem::Requirement
54
- none: false
55
54
  requirements:
56
55
  - - ! '>='
57
56
  - !ruby/object:Gem::Version
58
57
  version: '0'
59
58
  required_rubygems_version: !ruby/object:Gem::Requirement
60
- none: false
61
59
  requirements:
62
60
  - - ! '>='
63
61
  - !ruby/object:Gem::Version
64
62
  version: '0'
65
63
  requirements: []
66
64
  rubyforge_project:
67
- rubygems_version: 1.8.24
65
+ rubygems_version: 2.1.9
68
66
  signing_key:
69
- specification_version: 3
67
+ specification_version: 4
70
68
  summary: functional programming in ruby
71
69
  test_files:
72
70
  - spec/prelude_lambda_math_spec.rb
@@ -74,3 +72,4 @@ test_files:
74
72
  - spec/prelude_meta_spec.rb
75
73
  - spec/spec_helper.rb
76
74
  - test/test_prelude_performance.rb
75
+ has_rdoc: