mll 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (7) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +58 -21
  3. data/Rakefile +1 -0
  4. data/lib/mll.rb +105 -68
  5. data/mll.gemspec +1 -1
  6. data/spec/_spec.rb +168 -40
  7. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 812325964160837ba11226c5585e372463dd9fd7
4
- data.tar.gz: fb060b7f5a405a230b21a20c9cc8426e5bd7e19b
3
+ metadata.gz: ce709bc99f6cbd85ca763a4752346b0b5e4112cb
4
+ data.tar.gz: 0e6ba411ce044ecffbc476fcbefcb61a8cf18926
5
5
  SHA512:
6
- metadata.gz: 5fe15ad50531a0b9740847b01c27ed76e598d0345a0158b22474715a7fbb8bc917479c406ef1cac3580b167dd19b30bca820665888792657e8be6bc2a1f67b81
7
- data.tar.gz: dd3547ff6b62c5ecd29d91529aee42e1552cb0d90bde926e7d8e090cdcf1df7ca1792aa110835a82133127f2f33d2c56a6421ab2ca56e778acbead64537c7380
6
+ metadata.gz: 6464f5860f02778245155c5f7ec98b61bde188482ef2fb90593baf1cf72fbede13ddd47654288745684d0fdc314cbe3e2609284fcb53cd329c6175b288686845
7
+ data.tar.gz: 00014f6f4d963c1512f844703b39888f084ebe1495e2fedffc3abe0bc29db2af3f78b40618c3280560414b6729c6d490cd2923faf6397fb26645a891f7f7b657
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # MLL (Mathematica Language Library)
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/mll.svg)](http://badge.fury.io/rb/mll)
4
+
3
5
  ## What
4
6
 
5
7
  This gem isn't supposed to mimic all data types, exact syntax of Wolfram Mathematica or make Ruby able to make the same visualisations.
@@ -8,11 +10,13 @@ The main goal is to make Ruby more powerful by including the most used functions
8
10
 
9
11
  ## Why
10
12
 
13
+ 0. `::map` can map Arrays at specified depth!
11
14
  1. One of the most useful things is automatic zipping vectors (`Array`s) when you apply scalar functions to them. https://reference.wolfram.com/language/ref/Listable.html
12
15
  2. unlike Ruby's `Range` class, `::range` can handle negative `step` and even have `float` starting value
13
- 3. unlike Ruby's `Array#map`, `::table` can create multidimensional arrays with a single call, not nested
14
- 4. `#fold_list` was wanted [here](http://stackoverflow.com/q/1475808/322020) in Ruby while being already implemented as [FoldList[]](http://reference.wolfram.com/language/ref/FoldList.html) in Mathematica and [scanl](http://hackage.haskell.org/package/base-4.8.0.0/docs/Prelude.html#v:scanl) in Haskell
15
- 5. `#nest` (n times) and `#nest_list` for repetitive applying the same function -- `#nest_while` and `#nest_while_list` are going to be implemented later
16
+ 3. unlike Ruby's `Array.new`, `::table` can create multidimensional arrays with a single call, not nested
17
+ 4. `::fold_list` was wanted [here](http://stackoverflow.com/q/1475808/322020) in Ruby while being already implemented as [FoldList[]](http://reference.wolfram.com/language/ref/FoldList.html) in Mathematica and [scanl](http://hackage.haskell.org/package/base-4.8.0.0/docs/Prelude.html#v:scanl) in Haskell
18
+ 5. `::nest` (n times) and `::nest_list` for repetitive applying the same function -- `::nest_while` and `::nest_while_list` are going to be implemented later
19
+ 6. `::tally` -- shortcut to a probably the most common usage of `#group_by` -- calculating total occurences.
16
20
 
17
21
  ## How
18
22
 
@@ -20,11 +24,20 @@ The main goal is to make Ruby more powerful by including the most used functions
20
24
  MLL::range[[2, 3]] # => [1..2, 1..3]
21
25
  MLL::range[ 1..3 ] # => [1..1, 1..2, 1..3]
22
26
 
23
- MLL::table[ ->(i,j){ i+j }, [[1, 0, 1]], [[0, 2, 0]] ]
27
+ t = MLL::table[ ->(i,j){ i+j }, [[1, 0, 1]], [[0, 2, 0]] ]
24
28
  # => [[1, 3, 1],
25
29
  [0, 2, 0],
26
30
  [1, 3, 1]]
27
- MLL::table[ MLL.method(:times), 9, 9 ]
31
+ t = MLL::map[ ->(i){ [i] }, t, [2] ]
32
+ # => [[ [1], [3], [1] ],
33
+ [ [0], [2], [0] ],
34
+ [ [1], [3], [1] ]]
35
+ MLL::map[ ->(i){ -i }, t, [3] ]
36
+ # => [[ [-1], [-3], [-1] ],
37
+ [ [ 0], [-2], [ 0] ],
38
+ [ [-1], [-3], [-1] ]]
39
+
40
+ MLL::table[ MLL::times, 9, 9 ]
28
41
  # => [[1, 2, 3, 4, 5, 6, 7, 8, 9],
29
42
  [2, 4, 6, 8, 10, 12, 14, 16, 18],
30
43
  [3, 6, 9, 12, 15, 18, 21, 24, 27],
@@ -34,6 +47,10 @@ The main goal is to make Ruby more powerful by including the most used functions
34
47
  [7, 14, 21, 28, 35, 42, 49, 56, 63],
35
48
  [8, 16, 24, 32, 40, 48, 56, 64, 72],
36
49
  [9, 18, 27, 36, 45, 54, 63, 72, 81]]
50
+ # ::times means *
51
+ # ::divide means /
52
+ # ::subtract means -
53
+ # ::plus means +
37
54
 
38
55
  MLL::fold_list[ MLL::times, MLL::range[10] ]
39
56
  # => [1,2,6,24,120,720,5040,40320,362880,3628800]
@@ -42,10 +59,6 @@ The main goal is to make Ruby more powerful by including the most used functions
42
59
  # even of different dimensions with basic operations
43
60
  MLL::times[ [[1,2],[3,4]], [5,6] ]
44
61
  # => [[5,10], [18,24]]
45
- # ::times means *
46
- # ::divide means /
47
- # ::subtract means -
48
- # ::plus means +
49
62
 
50
63
  # http://en.wikipedia.org/wiki/Collatz_conjecture
51
64
  MLL::nest_list[ ->(i){ i.even? ? i/2 : (i*3+1)/2 }, 20, 10 ]
@@ -57,7 +70,12 @@ The main goal is to make Ruby more powerful by including the most used functions
57
70
  MLL::subdivide[ 5, 10, 4 ]
58
71
  # => [5.0, 6.25, 7.5, 8.75, 10.0]
59
72
 
60
- Note that to see some of above examples working you need `.to_a`, `.map(&:to_a)` or even `.to_a.map(&:to_a)` since lazyness is intensively used.
73
+ MLL::tally[ "the quick brown fox jumps over the lazy dog".chars ]
74
+ # => {"t"=>2, "h"=>2, "e"=>3, " "=>8, "q"=>1, "u"=>2, "i"=>1, "c"=>1, "k"=>1,
75
+ "b"=>1, "r"=>2, "o"=>4, "w"=>1, "n"=>1, "f"=>1, "x"=>1, "j"=>1, "m"=>1,
76
+ "p"=>1, "s"=>1, "v"=>1, "l"=>1, "a"=>1, "z"=>1, "y"=>1, "d"=>1, "g"=>1}
77
+
78
+ Note that to see some of above examples working in the same way you need `.to_a`, `.map(&:to_a)` or even `.to_a.map(&:to_a)` since lazyness is intensively used.
61
79
 
62
80
  ## Installation
63
81
 
@@ -77,15 +95,19 @@ or
77
95
 
78
96
  ```
79
97
  module MLL
80
- def self.fold_list
81
- lambda do |f, x, list = nil|
82
- # TODO use Ruby#inject ?
83
- def self.table
84
- lambda do |f, *args|
85
- [].tap do |result|
86
- }]].tap do |stack|
87
- stack.each do |ai, ri|
88
- # TODO try to make #table lazy (Enumerator instead of Array)
98
+ class << self
99
+ def fold_list
100
+ lambda do |f, x, list = nil|
101
+ # TODO use Ruby#inject ?
102
+ def map
103
+ # TODO validate depths
104
+ # TODO break on passing all depths
105
+ def table
106
+ lambda do |f, *args|
107
+ [].tap do |result|
108
+ }]].tap do |stack|
109
+ stack.each do |ai, ri|
110
+ # TODO try to make #table lazy (Enumerator instead of Array)
89
111
  # TODO not sure if we need any other kind of Listability except of #range[[Array]]
90
112
  ```
91
113
 
@@ -100,14 +122,29 @@ describe MLL do
100
122
  describe "List Manipulation" do
101
123
  describe "Constructing Lists" do
102
124
  describe "#table" do
103
- describe "Scope" do
125
+ describe "Scope:" do
104
126
  # TODO: "Make a triangular array:"
105
127
  describe "#range" do
106
128
  # TODO take from docs more examples that involve other functions
107
129
  describe "Applying Functions to Lists" do
108
130
  describe "#fold_list" do
109
- describe "Applications" do
131
+ describe "Applications:" do
110
132
  # TODO maybe move it to README.md
133
+ describe "#map" do
134
+ # TODO we'll need less nested mappings when we implement stop on depths depletion
135
+ describe "Details and Options:" do
136
+ example "levels n1 though n2" do
137
+ expect(map[->(i){ [i] }, [1,[2,[3,[4,[5,6]]]]], [2,4]].
138
+ # TODO smth _<>
139
+ # TODO "Level corresponds to the whole expression"
140
+ # TODO currying "Map[f][expr] is equivalent to Map[f,expr]"
141
+ describe "Scope:" do
142
+ # TODO "Map on all levels, starting at level" ant other about Infinity
143
+ describe "Properties & Relations:" do
144
+ # TODO #mapall
145
+ # TODO #mapthread ?
146
+ # TODO #mapindexed ?
147
+ # TODO "negative levels"
111
148
  # TODO http://reference.wolfram.com/language/guide/ElementsOfLists.html
112
149
  # TODO http://reference.wolfram.com/language/guide/RearrangingAndRestructuringLists.html
113
150
  # TODO http://reference.wolfram.com/language/guide/MathematicalAndCountingOperationsOnLists.html
data/Rakefile CHANGED
@@ -26,6 +26,7 @@ task :todo do |t|
26
26
  end
27
27
  readme_file.puts "```"
28
28
  end
29
+ readme_file.truncate readme_file.pos
29
30
  end
30
31
  end
31
32
 
data/lib/mll.rb CHANGED
@@ -1,77 +1,114 @@
1
1
  module MLL
2
2
 
3
- def self.nest_list
4
- lambda do |f, expr, n|
5
- Enumerator.new do |e|
6
- e << expr
7
- n.times do
8
- e << expr = f.call(expr)
3
+ class << self
4
+
5
+ def tally
6
+ lambda do |list, test = ->(i,j){ i == j } | # TODO implement #sameq ?
7
+ h = Hash.new{ 0 }
8
+ keys = []
9
+ list.each do |item|
10
+ h[item] += 1 if keys.each do |key|
11
+ if test[key, item]
12
+ h[key] += 1
13
+ break
14
+ end
15
+ end
16
+ keys << item
9
17
  end
18
+ h
10
19
  end
11
20
  end
12
- end
13
- # def self.nest *args
14
- # nest_list(*args).last
15
- # end
16
- def self.nest
17
- lambda do |f, expr, n|
18
- n.times{ expr = f.call expr }
19
- expr
21
+
22
+ def nest_list
23
+ lambda do |f, expr, n|
24
+ Enumerator.new do |e|
25
+ e << expr
26
+ n.times do
27
+ e << expr = f.call(expr)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ # def self.nest *args
33
+ # nest_list(*args).last
34
+ # end
35
+ def nest
36
+ lambda do |f, expr, n|
37
+ n.times{ expr = f.call expr }
38
+ expr
39
+ end
20
40
  end
21
- end
22
41
 
23
- def self.fold_list
24
- lambda do |f, x, list = nil|
25
- x, *list = x.to_a unless list
26
- # TODO use Ruby#inject ?
27
- Enumerator.new do |e|
28
- e << x
29
- list.each do |i|
30
- e << x = f.call(x, i)
42
+ def fold_list
43
+ lambda do |f, x, list = nil|
44
+ x, *list = x.to_a unless list
45
+ # TODO use Ruby#inject ?
46
+ Enumerator.new do |e|
47
+ e << x
48
+ list.each do |i|
49
+ e << x = f.call(x, i)
50
+ end
31
51
  end
32
52
  end
33
53
  end
34
- end
35
54
 
36
- def self.table
37
- lambda do |f, *args|
38
- [].tap do |result|
39
- [[result, args.map{ |r| # add lazy?
40
- r.respond_to?(:map) && r.first.respond_to?(:map) ?
41
- r.first : range[*r]
42
- }]].tap do |stack|
43
- stack.each do |ai, ri|
44
- # TODO try to make #table lazy (Enumerator instead of Array)
45
- # "no implicit conversion of Enumerator::Lazy into Array"
46
- # "undefined method `replace' for #<Enumerator::Lazy: []>"
47
- ai.replace ri.first.map{ |i|
48
- if ri.size == 1
49
- f.call(*ai, i)
50
- else
51
- [*ai.dup, i].tap{ |t| stack << [t, ri.drop(1)] }
52
- end
53
- }
55
+ def map
56
+ # TODO validate depths
57
+ # TODO break on passing all depths
58
+ lambda do |f, list, depths = [1]|
59
+ depths = Range.new(*depths) if depths.size == 2
60
+ depths = Range.new(1,depths) if depths.is_a? Integer
61
+ g = lambda do |list, depth|
62
+ next list unless list.respond_to? :map
63
+ temp = list.lazy.map{ |i| g[i, depth + 1] }
64
+ temp = temp.map &f if depths.include? depth
65
+ temp
66
+ end
67
+ g[list, 1]
68
+ end
69
+ end
70
+
71
+ def table
72
+ lambda do |f, *args|
73
+ [].tap do |result|
74
+ [[result, args.map{ |r| # add lazy?
75
+ r.respond_to?(:map) && r.first.respond_to?(:map) ?
76
+ r.first : range[*r]
77
+ }]].tap do |stack|
78
+ stack.each do |ai, ri|
79
+ # TODO try to make #table lazy (Enumerator instead of Array)
80
+ # "no implicit conversion of Enumerator::Lazy into Array"
81
+ # "undefined method `replace' for #<Enumerator::Lazy: []>"
82
+ ai.replace ri.first.map{ |i|
83
+ if ri.size == 1
84
+ f.call(*ai, i)
85
+ else
86
+ [*ai.dup, i].tap{ |t| stack << [t, ri.drop(1)] }
87
+ end
88
+ }
89
+ end
54
90
  end
55
91
  end
56
92
  end
57
93
  end
58
- end
59
94
 
60
- def self.define_listable_function name, &block
61
- (class << self; self end).class_eval do
62
- define_method name do
63
- lambda do |*args|
64
- case args.map{ |i| i.respond_to? :map }
65
- when [true] ; args.first.lazy.map &method(name).call
66
- when [true, true] ; args.first.lazy.zip(args.last).map{ |i, j| send(name)[i, j] }
67
- when [true, false] ; args.first.lazy.map{ |i| send(name)[i, args.last] }
68
- when [false, true] ; args.last.lazy.map{ |i| send(name)[args.first, i] }
69
- else
70
- block.call *args
95
+ def define_listable_function name, &block
96
+ (class << self; self end).class_eval do
97
+ define_method name do
98
+ lambda do |*args|
99
+ case args.map{ |i| i.respond_to? :map }
100
+ when [true] ; args.first.lazy.map &method(name).call
101
+ when [true, true] ; args.first.lazy.zip(args.last).map{ |i, j| send(name)[i, j] }
102
+ when [true, false] ; args.first.lazy.map{ |i| send(name)[i, args.last] }
103
+ when [false, true] ; args.last.lazy.map{ |i| send(name)[args.first, i] }
104
+ else
105
+ block.call *args
106
+ end
71
107
  end
72
108
  end
73
109
  end
74
110
  end
111
+
75
112
  end
76
113
 
77
114
  # TODO not sure if we need any other kind of Listability except of #range[[Array]]
@@ -98,6 +135,20 @@ module MLL
98
135
  end
99
136
  end
100
137
 
138
+ def self.subdivide
139
+ lambda do |*args|
140
+ case args.size
141
+ when 1 ; subdivide[1, args[0]]
142
+ when 2 ; subdivide[0, args[0], args[1]]
143
+ when 3
144
+ # raise ArgumentError.new("can't divide into 0 parts") if args[2].zero?
145
+ range[args[0], args[1], (args[1] - args[0]) * 1.0 / args[2]]
146
+ else
147
+ raise ArgumentError.new("wrong number of arguments (#{args.size} for 1..3)")
148
+ end
149
+ end
150
+ end
151
+
101
152
  define_listable_function(:subtract) { |*args| raise ArgumentError.new("need two arguments") unless args.size == 2 ; args[0] - args[1] }
102
153
  define_listable_function(:divide) { |*args| raise ArgumentError.new("need two arguments") unless args.size == 2 ; args[0] / args[1] }
103
154
  define_listable_function(:_plus) { |*args| raise ArgumentError.new("need two arguments") unless args.size == 2 ; args[0] + args[1] }
@@ -120,18 +171,4 @@ module MLL
120
171
  define_orderless_function(:plus, 0) { |a, b| _plus.call a, b }
121
172
  define_orderless_function(:times, 1) { |a, b| _times.call a, b }
122
173
 
123
- def self.subdivide
124
- lambda do |*args|
125
- case args.size
126
- when 1 ; subdivide[1, args[0]]
127
- when 2 ; subdivide[0, args[0], args[1]]
128
- when 3
129
- # raise ArgumentError.new("can't divide into 0 parts") if args[2].zero?
130
- range[args[0], args[1], (args[1] - args[0]) * 1.0 / args[2]]
131
- else
132
- raise ArgumentError.new("wrong number of arguments (#{args.size} for 1..3)")
133
- end
134
- end
135
- end
136
-
137
174
  end
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "mll"
3
- spec.version = "1.1.0"
3
+ spec.version = "1.2.0"
4
4
  spec.authors = ["Victor Maslov"]
5
5
  spec.email = ["nakilon@gmail.com"]
6
6
  spec.summary = "Mathematica Language Library in Ruby"
@@ -38,7 +38,7 @@ describe MLL do
38
38
  expect{ subtract[0,0,0] }.to raise_error ArgumentError
39
39
  end
40
40
 
41
- describe "Basic Examples" do
41
+ describe "Basic Examples:" do
42
42
 
43
43
  example "subtract numbers" do
44
44
  expect(subtract[10,3]).to eq 7
@@ -46,7 +46,7 @@ describe MLL do
46
46
 
47
47
  end
48
48
 
49
- describe "Scope" do
49
+ describe "Scope:" do
50
50
 
51
51
  example "threads element‐wise over lists" do
52
52
  expect(subtract[[1,2,3,4],0.5]).to be_a Enumerator
@@ -79,7 +79,7 @@ describe MLL do
79
79
  expect{ divide[0,0,0] }.to raise_error ArgumentError
80
80
  end
81
81
 
82
- describe "Basic Examples" do
82
+ describe "Basic Examples:" do
83
83
 
84
84
  example "divide numbers" do
85
85
  expect(divide[77,11]).to eq 7
@@ -87,7 +87,7 @@ describe MLL do
87
87
 
88
88
  end
89
89
 
90
- describe "Scope" do
90
+ describe "Scope:" do
91
91
 
92
92
  example "threads element‐wise over lists" do
93
93
  expect(divide[[2,3,4,5],2.0]).to be_a Enumerator
@@ -108,7 +108,7 @@ describe MLL do
108
108
 
109
109
  end
110
110
 
111
- describe "Applications" do
111
+ describe "Applications:" do
112
112
 
113
113
  example "successive ratios in a list" do
114
114
  skip "waiting for Rationals to be used"
@@ -121,7 +121,7 @@ describe MLL do
121
121
  # http://reference.wolfram.com/language/ref/Plus.html
122
122
  describe "#plus" do
123
123
 
124
- describe "Details" do
124
+ describe "Details:" do
125
125
 
126
126
  example "#plus[] is taken to be 0" do
127
127
  expect(plus[]).to eq 0
@@ -132,7 +132,7 @@ describe MLL do
132
132
 
133
133
  end
134
134
 
135
- describe "Basic Examples" do
135
+ describe "Basic Examples:" do
136
136
 
137
137
  example "sums numbers" do
138
138
  expect(plus[2,3,4]).to eq 9
@@ -149,7 +149,7 @@ describe MLL do
149
149
 
150
150
  end
151
151
 
152
- describe "Scope" do
152
+ describe "Scope:" do
153
153
 
154
154
  example "threads element‐wise over lists" do
155
155
  expect(plus[[10,20,30],[1,2,3]]).to be_a Enumerator
@@ -164,7 +164,7 @@ describe MLL do
164
164
 
165
165
  end
166
166
 
167
- describe "Possible Issues" do
167
+ describe "Possible Issues:" do
168
168
 
169
169
  # idk why not in 'Properties & Relations'
170
170
  example "accumulate makes a cumulative sum" do
@@ -179,7 +179,7 @@ describe MLL do
179
179
  # http://reference.wolfram.com/language/ref/Times.html
180
180
  describe "#times" do
181
181
 
182
- describe "Details" do
182
+ describe "Details:" do
183
183
 
184
184
  example "#times[] is taken to be 1" do
185
185
  expect(times[]).to eq 1
@@ -190,7 +190,7 @@ describe MLL do
190
190
 
191
191
  end
192
192
 
193
- describe "Basic Examples" do
193
+ describe "Basic Examples:" do
194
194
 
195
195
  example "multiplies numbers" do
196
196
  expect(times[2,3,4]).to eq 24
@@ -206,7 +206,7 @@ describe MLL do
206
206
 
207
207
  end
208
208
 
209
- describe "Scope" do
209
+ describe "Scope:" do
210
210
 
211
211
  example "threads element‐wise over lists" do
212
212
  expect(times[[2,3],[4,5]]).to be_a Enumerator
@@ -236,7 +236,7 @@ describe MLL do
236
236
  # http://reference.wolfram.com/language/ref/Table.html
237
237
  describe "#table" do
238
238
 
239
- describe "Details" do
239
+ describe "Details:" do
240
240
 
241
241
  example "#table[expr,spec1,spec2] is effectively equivalent to #table[#table[expr,spec2],spec1]" do
242
242
  expect(table[->(i,j){ [i,j] }, 2, 3]).to eq table[->(i){ table[->(j){ [i,j] }, 3] }, 2]
@@ -244,7 +244,7 @@ describe MLL do
244
244
 
245
245
  end
246
246
 
247
- describe "Basic Examples" do
247
+ describe "Basic Examples:" do
248
248
 
249
249
  example "a table of the first 10 squares" do
250
250
  expect(table[->(i){ i**2 }, 10]).to be_a Array
@@ -271,7 +271,7 @@ describe MLL do
271
271
  ]
272
272
  end
273
273
 
274
- describe "Scope" do
274
+ describe "Scope:" do
275
275
 
276
276
  # TODO: "Make a triangular array:"
277
277
 
@@ -284,7 +284,7 @@ describe MLL do
284
284
 
285
285
  end
286
286
 
287
- describe "Applications" do
287
+ describe "Applications:" do
288
288
 
289
289
  example "column table(binomial, )" do
290
290
  skip "#binomial and #column are yet to be implemented"
@@ -309,7 +309,7 @@ describe MLL do
309
309
  expect{ range[1,2,0] }.to raise_error ArgumentError
310
310
  end
311
311
 
312
- describe "Details" do
312
+ describe "Details:" do
313
313
 
314
314
  example "the arguments need not be integers" do
315
315
  expect(range[0.25,2.9,1.25]).to be_a Enumerator
@@ -318,7 +318,7 @@ describe MLL do
318
318
 
319
319
  end
320
320
 
321
- describe "Basic Examples" do
321
+ describe "Basic Examples:" do
322
322
 
323
323
  example "range(n)" do
324
324
  expect(range[4]).to be_a Enumerator
@@ -344,7 +344,7 @@ describe MLL do
344
344
  expect(range[3,1,-1].to_a).to eq [3,2,1]
345
345
  end
346
346
 
347
- describe "Generalizations & Extensions" do
347
+ describe "Generalizations & Extensions:" do
348
348
 
349
349
  example "use a list of range specifications" do
350
350
  expect(range[[5,2,6,3]]).to be_a Enumerator
@@ -356,7 +356,7 @@ describe MLL do
356
356
 
357
357
  end
358
358
 
359
- describe "Applications" do
359
+ describe "Applications:" do
360
360
 
361
361
  example "produce a geometric sequence" do
362
362
  skip "#power is yet to be implemented"
@@ -366,7 +366,7 @@ describe MLL do
366
366
 
367
367
  end
368
368
 
369
- describe "Properties & Relations" do
369
+ describe "Properties & Relations:" do
370
370
 
371
371
  example "#range[imin,imax,di] is equivalent to #table[i,[imin,imax,di]]" do
372
372
  expect(range[2,8,3].to_a).to eq table[->(i){ i }, [2,8,3]]
@@ -386,7 +386,7 @@ describe MLL do
386
386
  expect(range[1..3].to_a.map(&:to_a)).to eq [[1],[1,2],[1,2,3]]
387
387
  end
388
388
 
389
- describe "Neat Examples" do
389
+ describe "Neat Examples:" do
390
390
 
391
391
  example "make nested ranges" do
392
392
  range[range[range[3]]].tap do |o|
@@ -418,7 +418,7 @@ describe MLL do
418
418
  # expect{ subdivide[0] }.to raise_error ArgumentError
419
419
  # end
420
420
 
421
- describe "Details" do
421
+ describe "Details:" do
422
422
 
423
423
  example "generates a list of length n+1" do
424
424
  expect(subdivide[5]).to be_a Enumerator
@@ -427,7 +427,7 @@ describe MLL do
427
427
 
428
428
  end
429
429
 
430
- describe "Basic Examples" do
430
+ describe "Basic Examples:" do
431
431
 
432
432
  example "subdivide the unit interval into 4 equal parts" do
433
433
  expect(subdivide[4]).to be_a Enumerator
@@ -450,7 +450,7 @@ describe MLL do
450
450
 
451
451
  end
452
452
 
453
- describe "Properties & Relations" do
453
+ describe "Properties & Relations:" do
454
454
 
455
455
  example "subdivide[xmin,xmax,n] is equivalent to xmin+(xmax-xmin)Range[0,n]/n" do
456
456
  expect(subdivide[2,10,4].to_a).to eq plus[2,divide[times[10-2,range[0,4]],4]].to_a
@@ -468,7 +468,7 @@ describe MLL do
468
468
  expect(nest_list[->(*args){}, 0, 5].to_a.size).to eq 6
469
469
  end
470
470
 
471
- describe "Basic Examples" do
471
+ describe "Basic Examples:" do
472
472
 
473
473
  example "???" do
474
474
  skip "#cos (or #sqrt or anything unar is yet to be implemented"
@@ -476,7 +476,7 @@ describe MLL do
476
476
 
477
477
  end
478
478
 
479
- describe "Scope" do
479
+ describe "Scope:" do
480
480
 
481
481
  example "nesting can return a single number" do
482
482
  skip "#sqrt is yet to be implemented"
@@ -484,7 +484,7 @@ describe MLL do
484
484
 
485
485
  end
486
486
 
487
- describe "Applications" do
487
+ describe "Applications:" do
488
488
 
489
489
  example "powers of 2" do
490
490
  expect(nest_list[->(i){ 2*i }, 1, 10]).to be_a Enumerator
@@ -500,7 +500,7 @@ describe MLL do
500
500
  end
501
501
  example "random walk" do
502
502
  expect(( r = Random.new(0); nest_list[->(i){ i+[-1,1][r.rand(2)] }, 0, 20] )).to be_a Enumerator
503
- expect(( r = Random.new(0); nest_list[->(i){ i+[-1,1][r.rand(2)] }, 0, 20].to_a )).to eq [0,-1,0,1,0,1,2,3,4,5,6,7,6,5,6,5,4,3,2,1,2]
503
+ expect(( r = Random.new(0); nest_list[->(i){ i+[-1,1][r.rand(2)] }, 0, 20] ).to_a).to eq [0,-1,0,1,0,1,2,3,4,5,6,7,6,5,6,5,4,3,2,1,2]
504
504
  end
505
505
  example "successively rotate a list" do
506
506
  expect(nest_list[->(i){ i.rotate 1 }, [1,2,3,4], 4]).to be_a Enumerator
@@ -509,7 +509,7 @@ describe MLL do
509
509
 
510
510
  end
511
511
 
512
- describe "Properties & Relations" do
512
+ describe "Properties & Relations:" do
513
513
 
514
514
  example "#nest gives the last element of #nest_list" do
515
515
  expect(nest_list[->(i){ i*2 }, 3, 4].to_a.last).to eq nest[->(i){ i*2 }, 3, 4]
@@ -536,7 +536,7 @@ describe MLL do
536
536
  # http://reference.wolfram.com/language/ref/FoldList.html
537
537
  describe "#fold_list" do
538
538
 
539
- describe "Details" do
539
+ describe "Details:" do
540
540
 
541
541
  example "with a length n list, #fold_list generates a list of length n+1" do
542
542
  skip "waiting got Wolfram team to fix the reported bug"
@@ -548,7 +548,7 @@ describe MLL do
548
548
 
549
549
  end
550
550
 
551
- describe "Basic Examples" do
551
+ describe "Basic Examples:" do
552
552
 
553
553
  example "cumulative sums of the elements of the list" do
554
554
  expect(fold_list[plus,5,[1,2,3,4]]).to be_a Enumerator
@@ -565,12 +565,12 @@ describe MLL do
565
565
 
566
566
  end
567
567
 
568
- describe "Applications" do
568
+ describe "Applications:" do
569
569
 
570
570
  # TODO maybe move it to README.md
571
571
  example "generate a random walk" do
572
572
  expect(( r = Random.new(0); fold_list[plus, 0, Array.new(20){ [-1,1][r.rand(2)] }] )).to be_a Enumerator
573
- expect(( r = Random.new(0); fold_list[plus, 0, Array.new(20){ [-1,1][r.rand(2)] }].to_a )).to eq [0,-1,0,1,0,1,2,3,4,5,6,7,6,5,6,5,4,3,2,1,2]
573
+ expect(( r = Random.new(0); fold_list[plus, 0, Array.new(20){ [-1,1][r.rand(2)] }] ).to_a).to eq [0,-1,0,1,0,1,2,3,4,5,6,7,6,5,6,5,4,3,2,1,2]
574
574
  end
575
575
 
576
576
  example "find successively deeper parts in an expression" do
@@ -580,7 +580,7 @@ describe MLL do
580
580
 
581
581
  end
582
582
 
583
- describe "Properties & Relations" do
583
+ describe "Properties & Relations:" do
584
584
 
585
585
  example "makes a list of length n+1" do
586
586
  expect(fold_list[->{}, 0, [*1..10]]).to be_a Enumerator
@@ -601,7 +601,7 @@ describe MLL do
601
601
 
602
602
  end
603
603
 
604
- describe "Neat Examples" do
604
+ describe "Neat Examples:" do
605
605
 
606
606
  example "compute the minimum number of coins of different value needed to make up an amount" do
607
607
  skip "at least #mod is yet to be implemented"
@@ -611,6 +611,85 @@ describe MLL do
611
611
 
612
612
  end
613
613
 
614
+ # http://reference.wolfram.com/language/ref/Map.html
615
+ describe "#map" do
616
+
617
+ # TODO we'll need less nested mappings when we implement stop on depths depletion
618
+
619
+ describe "Details and Options:" do
620
+
621
+ example "levels n1 though n2" do
622
+ expect(map[->(i){ [i] }, [1,[2,[3,[4,[5,6]]]]], [2,4]]).to be_a Enumerator
623
+ expect(map[->(i){ [i] }, [1,[2,[3,[4,[5,6]]]]], [2,4]].
624
+ to_a.map{ |i| i.respond_to?(:to_a) ? i.
625
+ to_a.map{ |i| i.respond_to?(:to_a) ? i.
626
+ to_a.map{ |i| i.respond_to?(:to_a) ? i.
627
+ to_a.map{ |i| i.respond_to?(:to_a) ? i.
628
+ to_a.map{ |i| i.respond_to?(:to_a) ? i.
629
+ to_a.map{ |i| i.respond_to?(:to_a) ? i.
630
+ to_a.map{ |i| i.respond_to?(:to_a) ? i.to_a : i } : i } : i } : i } : i } : i } : i }
631
+ # TODO smth _<>
632
+ ).to eq [1,[[2],[[[3],[[[4],[[5,6]]]]]]]]
633
+ end
634
+
635
+ # TODO "Level corresponds to the whole expression"
636
+ # TODO currying "Map[f][expr] is equivalent to Map[f,expr]"
637
+
638
+ end
639
+
640
+ describe "Basic Examples:" do
641
+
642
+ example "???" do
643
+ expect(map[range, [1,2,3]]).to be_a Enumerator
644
+ expect(map[range, [1,2,3]].to_a.map(&:to_a)).to eq [[1],[1,2],[1,2,3]]
645
+ end
646
+ example "use explicit pure functions" do
647
+ expect(map[->(i){ i**2 }, [1,2,3,4]]).to be_a Enumerator
648
+ expect(map[->(i){ i**2 }, [1,2,3,4]].to_a).to eq [1,4,9,16]
649
+ end
650
+ example "map at top level" do
651
+ expect(map[->(i){ [i] }, [[1,2],[3,4,5]]]).to be_a Enumerator
652
+ expect(map[->(i){ [i] }, [[1,2],[3,4,5]]].to_a.map{ |i| i.to_a.map &:to_a }).to eq [[[1,2]],[[3,4,5]]]
653
+ end
654
+ example "map at level 2" do
655
+ expect(map[->(i){ [i] }, [[1,2],[3,4,5]], [2]]).to be_a Enumerator
656
+ expect(map[->(i){ [i] }, [[1,2],[3,4,5]], [2]].to_a.map(&:to_a)).to eq [[[1],[2]],[[3],[4],[5]]]
657
+ end
658
+ example "map at levels 1 and 2" do
659
+ expect(map[->(i){ [i] }, [[1,2],[3,4,5]], 2]).to be_a Enumerator
660
+ expect(map[->(i){ [i] }, [[1,2],[3,4,5]], 2].to_a.map{ |i| i.to_a.map(&:to_a) }).to eq [[[[1],[2]]],[[[3],[4],[5]]]]
661
+ end
662
+
663
+ end
664
+
665
+ describe "Scope:" do
666
+ # TODO "Map on all levels, starting at level" ant other about Infinity
667
+ end
668
+
669
+ describe "Properties & Relations:" do
670
+
671
+ example "leaves are visited before roots" do
672
+ skip "waiting for infinite map to be implemented"
673
+ log = []
674
+ map[log.method(:<<), [[1,2],[3,4,5]]]
675
+ expect(log).to eq [1,2,[1,2],3,4,5,[3,4,5],[[1,2],[3,4,5]]]
676
+ end
677
+
678
+ # TODO #mapall
679
+
680
+ # TODO #mapthread ?
681
+ # TODO #mapindexed ?
682
+
683
+ # TODO "negative levels"
684
+
685
+ example "#scan does the same as #map, but without returning a result" do
686
+ skip "#scan is yet to be implemented"
687
+ end
688
+
689
+ end
690
+
691
+ end
692
+
614
693
  end
615
694
 
616
695
  # TODO http://reference.wolfram.com/language/guide/ElementsOfLists.html
@@ -630,7 +709,7 @@ describe MLL do
630
709
  # http://reference.wolfram.com/language/ref/Nest.html
631
710
  describe "#nest" do
632
711
 
633
- describe "Basic Examples" do
712
+ describe "Basic Examples:" do
634
713
 
635
714
  example "the function to nest can be a pure function" do
636
715
  expect(nest[->(i){ (1+i)**2 }, 1, 3]).to eq 676
@@ -638,7 +717,7 @@ describe MLL do
638
717
 
639
718
  end
640
719
 
641
- describe "Scope" do
720
+ describe "Scope:" do
642
721
 
643
722
  example "nesting can return a single number" do
644
723
  skip "#sqrt is yet to be implemented"
@@ -646,7 +725,7 @@ describe MLL do
646
725
 
647
726
  end
648
727
 
649
- describe "Applications" do
728
+ describe "Applications:" do
650
729
 
651
730
  example "newton iterations for" do
652
731
  skip "waiting for Rationals to be used"
@@ -657,7 +736,7 @@ describe MLL do
657
736
 
658
737
  end
659
738
 
660
- describe "Properties & Relations" do
739
+ describe "Properties & Relations:" do
661
740
 
662
741
  example "Ruby#inject automatically inserts second arguments from a list" do
663
742
  expect(nest[->(i){ i*2 }, 3, 4]).to eq ([2]*4).inject(3){ |i,j| i*j }
@@ -673,6 +752,55 @@ describe MLL do
673
752
 
674
753
  end
675
754
 
755
+ # http://reference.wolfram.com/language/guide/NumericalData.html
756
+ describe "Numerical Data" do
757
+
758
+ # http://reference.wolfram.com/language/ref/Tally.html
759
+ describe "#tally" do
760
+
761
+ describe "Details:" do
762
+
763
+ example "#tally[list] is equivalent to #tally[list,#sameq]" do
764
+ skip "#sameq is yet to be implemented"
765
+ end
766
+
767
+ end
768
+
769
+ describe "Basic Examples:" do
770
+
771
+ example "obtain tallies for a list" do
772
+ expect(tally[[1, 1, 2, 1, 3, 2, 1]]).to be_a Hash
773
+ expect(tally[[1, 1, 2, 1, 3, 2, 1]]).to eq({1=>4, 2=>2, 3=>1})
774
+ end
775
+
776
+ example "use test argument to count elements with the same class" do
777
+ expect(tally[[[1,2], [1,2,3,4], 1, [1,2,3,4], 1], ->(i,j){ i.class == j.class }]).to be_a Hash
778
+ expect(tally[[[1,2], [1,2,3,4], 1, [1,2,3,4], 1], ->(i,j){ i.class == j.class }]).to eq({[1,2]=>3, 1=>2})
779
+ end
780
+
781
+ example "count the instances of randomly generated integers" do
782
+ expect(( r = Random.new(0); tally[Array.new(50){ r.rand 10 }] )).to be_a Hash
783
+ expect(( r = Random.new(0); tally[Array.new(50){ r.rand 10 }] )).to eq({5=>4, 0=>6, 3=>10, 7=>7, 9=>5, 2=>4, 4=>3, 6=>2, 8=>5, 1=>4})
784
+ end
785
+
786
+ end
787
+
788
+ describe "Properties & Relations:" do
789
+
790
+ example "elements with highest frequencies are given by #commonest" do
791
+ skip "#commonest is yet to be implemented"
792
+ end
793
+
794
+ example "#tally is a discrete analog of #bincounts" do
795
+ skip "#bincounts is yet to be implemented"
796
+ end
797
+
798
+ end
799
+
800
+ end
801
+
802
+ end
803
+
676
804
  end
677
805
 
678
806
  # TODO http://reference.wolfram.com/language/guide/HandlingArraysOfData.html
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mll
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Victor Maslov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-12 00:00:00.000000000 Z
11
+ date: 2015-07-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler