mll 1.2.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (7) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +33 -11
  3. data/Rakefile +9 -12
  4. data/lib/mll.rb +51 -23
  5. data/mll.gemspec +1 -1
  6. data/spec/_spec.rb +186 -56
  7. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ce709bc99f6cbd85ca763a4752346b0b5e4112cb
4
- data.tar.gz: 0e6ba411ce044ecffbc476fcbefcb61a8cf18926
3
+ metadata.gz: 1bfa93d983183ee395ce32f023a9536220884f0d
4
+ data.tar.gz: fd3504c892015ccf15a5f451c7877115186a138b
5
5
  SHA512:
6
- metadata.gz: 6464f5860f02778245155c5f7ec98b61bde188482ef2fb90593baf1cf72fbede13ddd47654288745684d0fdc314cbe3e2609284fcb53cd329c6175b288686845
7
- data.tar.gz: 00014f6f4d963c1512f844703b39888f084ebe1495e2fedffc3abe0bc29db2af3f78b40618c3280560414b6729c6d490cd2923faf6397fb26645a891f7f7b657
6
+ metadata.gz: 38fd3e00c764eae431fa980369b2f7deff86908529343a3fb07fe37ad6c02e354b87e9ebdfd13a1581f9af8b4e3ce7cd00547840b78132a43c2ecede1ffa135d
7
+ data.tar.gz: f4f393855791bf20d726cecef3d6858a7f9cde8267b91abd59a413d689b0a3e613113958bab3c3b33205771eec42f56cd8fe7dca8cb9170f737ee2dd69f7a5fe
data/README.md CHANGED
@@ -2,13 +2,13 @@
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/mll.svg)](http://badge.fury.io/rb/mll)
4
4
 
5
- ## What
5
+ ### What
6
6
 
7
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
8
 
9
9
  The main goal is to make Ruby more powerful by including the most used functions, that Ruby lacks, such as `Table[]`, `FoldList[]`, etc. Visualisations are possible later by using additional gems.
10
10
 
11
- ## Why
11
+ ### Why
12
12
 
13
13
  0. `::map` can map Arrays at specified depth!
14
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
@@ -18,7 +18,7 @@ The main goal is to make Ruby more powerful by including the most used functions
18
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
19
  6. `::tally` -- shortcut to a probably the most common usage of `#group_by` -- calculating total occurences.
20
20
 
21
- ## How
21
+ ### How
22
22
 
23
23
  MLL::range[ 2, 3 ] # => 2..3
24
24
  MLL::range[[2, 3]] # => [1..2, 1..3]
@@ -77,11 +77,11 @@ The main goal is to make Ruby more powerful by including the most used functions
77
77
 
78
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.
79
79
 
80
- ## Installation
80
+ ### Installation
81
81
 
82
82
  $ gem install mll
83
83
 
84
- ## Testing with RSpec before contributing
84
+ ### Testing with RSpec before contributing
85
85
 
86
86
  rspec
87
87
 
@@ -89,15 +89,22 @@ or
89
89
 
90
90
  rake spec
91
91
 
92
- ## TODO (this section is filled automatically by `rake todo` task -- do not remove)
92
+ ### TODO (this section is filled automatically by `rake todo` task -- do not remove)
93
93
 
94
94
  #### lib/mll.rb
95
95
 
96
96
  ```
97
97
  module MLL
98
98
  class << self
99
+ def dimensions
100
+ lambda do |list, limit = nil|
101
+ enumerator = Enumerator.new do |e|
102
+ while list.map(&:class).uniq == [Array] &&
103
+ # TODO refactor into depth-first yielding
104
+ def nest_while
105
+ # TODO finish me
99
106
  def fold_list
100
- lambda do |f, x, list = nil|
107
+ lambda do |x, list, f = nil|
101
108
  # TODO use Ruby#inject ?
102
109
  def map
103
110
  # TODO validate depths
@@ -118,6 +125,8 @@ module MLL
118
125
  # TODO @fraggedICE wishes using Rational -- would also allow implementing more examples
119
126
  # TODO elegantly get rid of repetitive type checks
120
127
  # TODO ? let(:fake_lambda){ ->(*args){fail} }
128
+ # TODO rewrite all Lazy#to_a into Lazy#force (it's not recursive and not documented)
129
+ # TODO maybe make indexes count from 0 not 1
121
130
  describe MLL do
122
131
  describe "List Manipulation" do
123
132
  describe "Constructing Lists" do
@@ -134,7 +143,7 @@ describe MLL do
134
143
  # TODO we'll need less nested mappings when we implement stop on depths depletion
135
144
  describe "Details and Options:" do
136
145
  example "levels n1 though n2" do
137
- expect(map[->(i){ [i] }, [1,[2,[3,[4,[5,6]]]]], [2,4]].
146
+ expect(map[[1,[2,[3,[4,[5,6]]]]], [2,4], ->(i){ [i] }].
138
147
  # TODO smth _<>
139
148
  # TODO "Level corresponds to the whole expression"
140
149
  # TODO currying "Map[f][expr] is equivalent to Map[f,expr]"
@@ -145,14 +154,27 @@ describe MLL do
145
154
  # TODO #mapthread ?
146
155
  # TODO #mapindexed ?
147
156
  # TODO "negative levels"
148
- # TODO http://reference.wolfram.com/language/guide/ElementsOfLists.html
149
157
  # TODO http://reference.wolfram.com/language/guide/RearrangingAndRestructuringLists.html
150
158
  # TODO http://reference.wolfram.com/language/guide/MathematicalAndCountingOperationsOnLists.html
151
159
  describe "Functional Programming" do
152
160
  describe "Iteratively Applying Functions" do
153
161
  # TODO move #nest_list and #fold_list and others here?
154
- describe "#nest" do
155
- # TODO neat graphic examples
162
+ # TODO examples in README.rb
163
+ describe "#nest_while" do
164
+ describe "Details:" do
165
+ # TODO a lot
166
+ describe "Scope:" do
167
+ # TODO "always compare all values generated" do
168
+ # TODO "compare the last two values generated" do
169
+ # TODO "start comparisons after 4 iterations, and compare using the 4 last values" do
170
+ # TODO "start comparisons after 4 iterations, and compare using the 6 last values" do
171
+ # TODO example "stop after at most 4 iterations, even if the test is still true" do
172
+ describe "Generalizations & Extensions:" do
173
+ # TODO "return the last value for which the condition was still true" do
174
+ describe "Applications:" do
175
+ # TODO example "find the next twin prime after 888" do
176
+ describe "Properties & Relations:" do
177
+ # TODO "#nest_while can be expressed in terms of a while loop" do
156
178
  # TODO http://reference.wolfram.com/language/guide/HandlingArraysOfData.html
157
179
  # TODO http://reference.wolfram.com/language/guide/ComputationWithStructuredDatasets.html
158
180
  ```
data/Rakefile CHANGED
@@ -6,32 +6,29 @@ task :todo do |t|
6
6
  fail unless File.exist? "README.md"
7
7
  File.open("README.md", "r+") do |readme_file|
8
8
  # begin readme_file.gets end until $_[/^## TODO/]
9
- readme_file.gets "## TODO"
9
+ readme_file.gets "### TODO"
10
10
  readme_file.gets
11
11
  %w{ lib/mll.rb spec/_spec.rb }.each do |file|
12
12
  readme_file.puts "", "#### #{file}", "", "```"
13
13
  stack = []
14
- lines = []
15
- File.foreach(file).with_index do |line, i|
14
+ File.foreach(file) do |line|
16
15
  next unless shift = /\S/ =~ line
17
16
  depth = shift / 2
18
- stack[depth] = i
19
- lines |= stack.take(depth + 1) if line[/^\s*# TODO/]
20
- end
21
- next_line_to_print = lines.shift
22
- File.foreach(file).with_index do |line, i|
23
- next unless i == next_line_to_print
24
- readme_file.puts line
25
- next_line_to_print = lines.shift
17
+ stack[depth] = line
18
+ if line[/^\s*# TODO/]
19
+ readme_file.puts stack.take(depth + 1).compact
20
+ stack.clear
21
+ end
26
22
  end
27
23
  readme_file.puts "```"
28
24
  end
29
25
  readme_file.truncate readme_file.pos
30
26
  end
27
+ puts `md5 README.md`
31
28
  end
32
29
 
33
30
  RSpec::Core::RakeTask.new(:spec) do |t|
34
31
  t.verbose = false
35
32
  end
36
33
 
37
- task :default => %w{ todo spec }
34
+ task :default => %w{ spec todo }
data/lib/mll.rb CHANGED
@@ -2,25 +2,44 @@ module MLL
2
2
 
3
3
  class << self
4
4
 
5
+ def dimensions
6
+ lambda do |list, limit = nil|
7
+ list = [list]
8
+ enumerator = Enumerator.new do |e|
9
+ # String.size shall not pass
10
+ while list.map(&:class).uniq == [Array] &&
11
+ list.map(&:size).uniq.size == 1
12
+ # TODO refactor into depth-first yielding
13
+ e << list.first.size
14
+ list.flatten! 1
15
+ end
16
+ end
17
+ limit ? enumerator.lazy.take(limit) : enumerator
18
+ end
19
+ end
20
+
5
21
  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
22
+ lambda do |list, test = nil| # implement #sameq ?
23
+ return Hash[ list.group_by{ |i| i }.map{ |k, v| [k, v.size] } ] unless test
24
+ Hash.new{ 0 }.tap do |result|
25
+ list.each do |item|
26
+ result[
27
+ list.find{ |key| test[key, item] }
28
+ ] += 1
15
29
  end
16
- keys << item
17
30
  end
18
- h
31
+ end
32
+ end
33
+
34
+ def nest
35
+ lambda do |expr, n, f|
36
+ n.times{ expr = f.call expr }
37
+ expr
19
38
  end
20
39
  end
21
40
 
22
41
  def nest_list
23
- lambda do |f, expr, n|
42
+ lambda do |expr, n, f|
24
43
  Enumerator.new do |e|
25
44
  e << expr
26
45
  n.times do
@@ -29,19 +48,21 @@ module MLL
29
48
  end
30
49
  end
31
50
  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 }
51
+
52
+ def nest_while
53
+ # TODO finish me
54
+ lambda do |expr, f, test|
55
+ expr = f[expr] while test[expr]
38
56
  expr
39
57
  end
40
58
  end
41
59
 
42
60
  def fold_list
43
- lambda do |f, x, list = nil|
44
- x, *list = x.to_a unless list
61
+ lambda do |x, list, f = nil|
62
+ unless f
63
+ f = list
64
+ x, *list = x.to_a
65
+ end
45
66
  # TODO use Ruby#inject ?
46
67
  Enumerator.new do |e|
47
68
  e << x
@@ -55,13 +76,14 @@ module MLL
55
76
  def map
56
77
  # TODO validate depths
57
78
  # TODO break on passing all depths
58
- lambda do |f, list, depths = [1]|
79
+ lambda do |list, depths, f = nil|
80
+ depths, f = [1], depths unless f
59
81
  depths = Range.new(*depths) if depths.size == 2
60
82
  depths = Range.new(1,depths) if depths.is_a? Integer
61
83
  g = lambda do |list, depth|
62
- next list unless list.respond_to? :map
84
+ next list unless list.is_a? Array
63
85
  temp = list.lazy.map{ |i| g[i, depth + 1] }
64
- temp = temp.map &f if depths.include? depth
86
+ temp = temp.lazy.map &f if depths.include? depth
65
87
  temp
66
88
  end
67
89
  g[list, 1]
@@ -170,5 +192,11 @@ module MLL
170
192
 
171
193
  define_orderless_function(:plus, 0) { |a, b| _plus.call a, b }
172
194
  define_orderless_function(:times, 1) { |a, b| _times.call a, b }
195
+
196
+ def self.mean
197
+ lambda do |list|
198
+ divide[times[plus[*list], 1.0], list.size]
199
+ end
200
+ end
173
201
 
174
202
  end
data/mll.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "mll"
3
- spec.version = "1.2.0"
3
+ spec.version = "2.1.0"
4
4
  spec.authors = ["Victor Maslov"]
5
5
  spec.email = ["nakilon@gmail.com"]
6
6
  spec.summary = "Mathematica Language Library in Ruby"
data/spec/_spec.rb CHANGED
@@ -14,6 +14,9 @@ require_relative File.join "..", "lib", "mll"
14
14
  # TODO elegantly get rid of repetitive type checks
15
15
  # TODO ? let(:fake_lambda){ ->(*args){fail} }
16
16
 
17
+ # TODO rewrite all Lazy#to_a into Lazy#force (it's not recursive and not documented)
18
+
19
+ # TODO maybe make indexes count from 0 not 1
17
20
 
18
21
  # http://reference.wolfram.com/language/guide/LanguageOverview.html
19
22
  describe MLL do
@@ -168,8 +171,8 @@ describe MLL do
168
171
 
169
172
  # idk why not in 'Properties & Relations'
170
173
  example "accumulate makes a cumulative sum" do
171
- expect(fold_list[plus, 0, [1,2,3]]).to be_a Enumerator
172
- expect(fold_list[plus, 0, [1,2,3]].to_a).to eq [0,1,3,6]
174
+ expect(fold_list[0, [1,2,3], plus]).to be_a Enumerator
175
+ expect(fold_list[0, [1,2,3], plus].to_a).to eq [0,1,3,6]
173
176
  end
174
177
 
175
178
  end
@@ -464,8 +467,8 @@ describe MLL do
464
467
  describe "#nest_list" do
465
468
 
466
469
  example "gives a list of length n+1" do
467
- expect(nest_list[->{}, 0, 5]).to be_a Enumerator
468
- expect(nest_list[->(*args){}, 0, 5].to_a.size).to eq 6
470
+ expect(nest_list[0, 5, ->(*){}]).to be_a Enumerator
471
+ expect(nest_list[0, 5, ->(*){}].to_a.size).to eq 6
469
472
  end
470
473
 
471
474
  describe "Basic Examples:" do
@@ -487,24 +490,24 @@ describe MLL do
487
490
  describe "Applications:" do
488
491
 
489
492
  example "powers of 2" do
490
- expect(nest_list[->(i){ 2*i }, 1, 10]).to be_a Enumerator
491
- expect(nest_list[->(i){ 2*i }, 1, 10].to_a).to eq [1,2,4,8,16,32,64,128,256,512,1024]
493
+ expect(nest_list[1, 10, ->(i){ 2*i }]).to be_a Enumerator
494
+ expect(nest_list[1, 10, ->(i){ 2*i }].to_a).to eq [1,2,4,8,16,32,64,128,256,512,1024]
492
495
  end
493
496
  example "iterates in the problem" do
494
- expect(nest_list[->(i){ i.even? ? i/2 : (i*3+1)/2 }, 100, 20]).to be_a Enumerator
495
- expect(nest_list[->(i){ i.even? ? i/2 : (i*3+1)/2 }, 100, 20].to_a).to eq [100,50,25,38,19,29,44,22,11,17,26,13,20,10,5,8,4,2,1,2,1]
497
+ expect(nest_list[100, 20, ->(i){ i.even? ? i/2 : (i*3+1)/2 }]).to be_a Enumerator
498
+ expect(nest_list[100, 20, ->(i){ i.even? ? i/2 : (i*3+1)/2 }].to_a).to eq [100,50,25,38,19,29,44,22,11,17,26,13,20,10,5,8,4,2,1,2,1]
496
499
  end
497
500
  example "linear congruential pseudorandom generator" do
498
- expect(nest_list[->(i){ (i*59)%101 }, 1, 15]).to be_a Enumerator
499
- expect(nest_list[->(i){ (i*59)%101 }, 1, 15].to_a).to eq [1,59,47,46,88,41,96,8,68,73,65,98,25,61,64,39]
501
+ expect(nest_list[1, 15, ->(i){ (i*59)%101 }]).to be_a Enumerator
502
+ expect(nest_list[1, 15, ->(i){ (i*59)%101 }].to_a).to eq [1,59,47,46,88,41,96,8,68,73,65,98,25,61,64,39]
500
503
  end
501
504
  example "random walk" do
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]
505
+ expect(( r = Random.new(0); nest_list[0, 20, ->(i){ i+[-1,1][r.rand(2)] }] )).to be_a Enumerator
506
+ expect(( r = Random.new(0); nest_list[0, 20, ->(i){ i+[-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]
504
507
  end
505
508
  example "successively rotate a list" do
506
- expect(nest_list[->(i){ i.rotate 1 }, [1,2,3,4], 4]).to be_a Enumerator
507
- expect(nest_list[->(i){ i.rotate 1 }, [1,2,3,4], 4].to_a).to eq [[1,2,3,4],[2,3,4,1],[3,4,1,2],[4,1,2,3],[1,2,3,4]]
509
+ expect(nest_list[[1,2,3,4], 4, ->(i){ i.rotate 1 }]).to be_a Enumerator
510
+ expect(nest_list[[1,2,3,4], 4, ->(i){ i.rotate 1 }].to_a).to eq [[1,2,3,4],[2,3,4,1],[3,4,1,2],[4,1,2,3],[1,2,3,4]]
508
511
  end
509
512
 
510
513
  end
@@ -512,16 +515,15 @@ describe MLL do
512
515
  describe "Properties & Relations:" do
513
516
 
514
517
  example "#nest gives the last element of #nest_list" do
515
- expect(nest_list[->(i){ i*2 }, 3, 4].to_a.last).to eq nest[->(i){ i*2 }, 3, 4]
518
+ expect(nest_list[3, 4, ->(i){ i*2 }].to_a.last).to eq nest[3, 4, ->(i){ i*2 }]
516
519
  end
517
-
518
520
  example "nesting zero times simply returns to the original argument" do
519
- expect(nest_list[->{fail}, 5, 0]).to be_a Enumerator
520
- expect(nest_list[->(*args){fail}, 5, 0].to_a).to eq [5]
521
+ expect(nest_list[5, 0, ->(*){fail}]).to be_a Enumerator
522
+ expect(nest_list[5, 0, ->(*){fail}].to_a).to eq [5]
521
523
  end
522
524
  example "#fold_list automatically inserts second arguments from a list" do
523
- expect(nest_list[->(i ){ i*2 }, 3, 4].to_a).to eq \
524
- fold_list[->(i,j){ i*j }, 3, [2]*4].to_a
525
+ expect(nest_list[3, 4, ->(i ){ i*2 }].to_a).to eq \
526
+ fold_list[3, [2]*4, ->(i,j){ i*j }].to_a
525
527
  end
526
528
 
527
529
  end
@@ -542,8 +544,8 @@ describe MLL do
542
544
  skip "waiting got Wolfram team to fix the reported bug"
543
545
  end
544
546
  example "#fold_list[f,list] is equivalent to #fold_list[f,[list][0],list[1..-1]]" do
545
- expect(fold_list[plus,[1,2,3]]).to be_a Enumerator
546
- expect(fold_list[plus,[1,2,3]].to_a).to eq fold_list[plus,1,[2,3]].to_a
547
+ expect(fold_list[[1,2,3], plus]).to be_a Enumerator
548
+ expect(fold_list[[1,2,3], plus].to_a).to eq fold_list[1, [2,3], plus].to_a
547
549
  end
548
550
 
549
551
  end
@@ -551,16 +553,16 @@ describe MLL do
551
553
  describe "Basic Examples:" do
552
554
 
553
555
  example "cumulative sums of the elements of the list" do
554
- expect(fold_list[plus,5,[1,2,3,4]]).to be_a Enumerator
555
- expect(fold_list[plus,5,[1,2,3,4]].to_a).to eq [5,6,8,11,15]
556
+ expect(fold_list[5, [1,2,3,4], plus]).to be_a Enumerator
557
+ expect(fold_list[5, [1,2,3,4], plus].to_a).to eq [5,6,8,11,15]
556
558
  end
557
559
  example "cumulative powers" do
558
- expect(fold_list[->(base, power){ base ** power },2,[3,2,1]]).to be_a Enumerator
559
- expect(fold_list[->(base, power){ base ** power },2,[3,2,1]].to_a).to eq [2,8,64,64]
560
+ expect(fold_list[2, [3,2,1], ->(base, power){ base ** power }]).to be_a Enumerator
561
+ expect(fold_list[2, [3,2,1], ->(base, power){ base ** power }].to_a).to eq [2,8,64,64]
560
562
  end
561
563
  example "start from the first element of the list" do
562
- expect(fold_list[plus,[1,2,3,4]]).to be_a Enumerator
563
- expect(fold_list[plus,[1,2,3,4]].to_a).to eq [1,3,6,10]
564
+ expect(fold_list[[1,2,3,4], plus]).to be_a Enumerator
565
+ expect(fold_list[[1,2,3,4], plus].to_a).to eq [1,3,6,10]
564
566
  end
565
567
 
566
568
  end
@@ -569,13 +571,13 @@ describe MLL do
569
571
 
570
572
  # TODO maybe move it to README.md
571
573
  example "generate a random walk" do
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]
574
+ expect(( r = Random.new(0); fold_list[0, Array.new(20){ [-1,1][r.rand(2)] }, plus] )).to be_a Enumerator
575
+ expect(( r = Random.new(0); fold_list[0, Array.new(20){ [-1,1][r.rand(2)] }, plus] ).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
576
  end
575
577
 
576
578
  example "find successively deeper parts in an expression" do
577
- expect(fold_list[->(list,index){ list[index] }, [[1,2],[3,[4,5],6,7],8], [1,1,0]]).to be_a Enumerator
578
- expect(fold_list[->(list,index){ list[index] }, [[1,2],[3,[4,5],6,7],8], [1,1,0]].to_a).to eq [[[1,2],[3,[4,5],6,7],8],[3,[4,5],6,7],[4,5],4]
579
+ expect(fold_list[[[1,2],[3,[4,5],6,7],8], [1,1,0], ->(list,index){ list[index] }]).to be_a Enumerator
580
+ expect(fold_list[[[1,2],[3,[4,5],6,7],8], [1,1,0], ->(list,index){ list[index] }].to_a).to eq [[[1,2],[3,[4,5],6,7],8],[3,[4,5],6,7],[4,5],4]
579
581
  end
580
582
 
581
583
  end
@@ -583,20 +585,20 @@ describe MLL do
583
585
  describe "Properties & Relations:" do
584
586
 
585
587
  example "makes a list of length n+1" do
586
- expect(fold_list[->{}, 0, [*1..10]]).to be_a Enumerator
587
- expect(fold_list[->(*args){}, 0, [*1..10]].to_a.size).to eq 11
588
+ expect(fold_list[0, [*1..10], ->(*){}]).to be_a Enumerator
589
+ expect(fold_list[0, [*1..10], ->(*){}].to_a.size).to eq 11
588
590
  end
589
591
  example "folding with an empty list does not apply the function at all" do
590
- expect(fold_list[->{}, 0, []]).to be_a Enumerator
591
- expect(fold_list[->(*args){}, 0, []].to_a).to eq [0]
592
+ expect(fold_list[0, [], ->(*){}]).to be_a Enumerator
593
+ expect(fold_list[0, [], ->(*){}].to_a).to eq [0]
592
594
  end
593
595
  example "Ruby#inject gives the last element of #fold_list" do
594
596
  f = ->(i,j){ i+j }
595
- expect(fold_list[f, [1,2,3]]).to be_a Enumerator
596
- expect(fold_list[f, [1,2,3]].to_a.last).to eq [1,2,3].inject(&f)
597
+ expect(fold_list[[1,2,3], f]).to be_a Enumerator
598
+ expect(fold_list[[1,2,3], f].to_a.last).to eq [1,2,3].inject(&f)
597
599
  end
598
600
  example "functions that ignore their second argument give the same result as in #nest_list" do
599
- expect(fold_list[->(i,_){ [i] }, 0, range[5]].to_a).to eq nest_list[->(i){ [i] }, 0, 5].to_a
601
+ expect(fold_list[0, range[5], ->(i,_){ [i] }].to_a).to eq nest_list[0, 5, ->(i){ [i] }].to_a
600
602
  end
601
603
 
602
604
  end
@@ -619,8 +621,8 @@ describe MLL do
619
621
  describe "Details and Options:" do
620
622
 
621
623
  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
+ expect(map[[1,[2,[3,[4,[5,6]]]]], [2,4], ->(i){ [i] }]).to be_a Enumerator
625
+ expect(map[[1,[2,[3,[4,[5,6]]]]], [2,4], ->(i){ [i] }].
624
626
  to_a.map{ |i| i.respond_to?(:to_a) ? i.
625
627
  to_a.map{ |i| i.respond_to?(:to_a) ? i.
626
628
  to_a.map{ |i| i.respond_to?(:to_a) ? i.
@@ -640,24 +642,24 @@ describe MLL do
640
642
  describe "Basic Examples:" do
641
643
 
642
644
  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
+ expect(map[[1,2,3], range]).to be_a Enumerator
646
+ expect(map[[1,2,3], range].to_a.map(&:to_a)).to eq [[1],[1,2],[1,2,3]]
645
647
  end
646
648
  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
+ expect(map[[1,2,3,4], ->(i){ i**2 }]).to be_a Enumerator
650
+ expect(map[[1,2,3,4], ->(i){ i**2 }].to_a).to eq [1,4,9,16]
649
651
  end
650
652
  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
+ expect(map[[[1,2],[3,4,5]], ->(i){ [i] }]).to be_a Enumerator
654
+ expect(map[[[1,2],[3,4,5]], ->(i){ [i] }].to_a.map{ |i| i.to_a.map &:to_a }).to eq [[[1,2]],[[3,4,5]]]
653
655
  end
654
656
  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
+ expect(map[[[1,2],[3,4,5]], [2], ->(i){ [i] }]).to be_a Enumerator
658
+ expect(map[[[1,2],[3,4,5]], [2], ->(i){ [i] }].to_a.map(&:to_a)).to eq [[[1],[2]],[[3],[4],[5]]]
657
659
  end
658
660
  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
+ expect(map[[[1,2],[3,4,5]], 2, ->(i){ [i] }]).to be_a Enumerator
662
+ expect(map[[[1,2],[3,4,5]], 2, ->(i){ [i] }].to_a.map{ |i| i.to_a.map(&:to_a) }).to eq [[[[1],[2]]],[[[3],[4],[5]]]]
661
663
  end
662
664
 
663
665
  end
@@ -692,7 +694,45 @@ describe MLL do
692
694
 
693
695
  end
694
696
 
695
- # TODO http://reference.wolfram.com/language/guide/ElementsOfLists.html
697
+ # http://reference.wolfram.com/language/guide/ElementsOfLists.html
698
+ describe "Elements of Lists" do
699
+
700
+ describe "#dimensions" do
701
+
702
+ describe "Basic Examples:" do
703
+
704
+ example "dimensions of a matrix" do
705
+ expect(dimensions[[[1,2,3],[4,5,6]]]).to be_a Enumerator
706
+ expect(dimensions[[[1,2,3],[4,5,6]]].to_a).to eq [2,3]
707
+ end
708
+ example "#dimensions counts only dimensions at which an expression is not 'ragged'" do
709
+ expect(dimensions[[[1,2,3],[4,5],[]]]).to be_a Enumerator
710
+ expect(dimensions[[[1,2,3],[4,5],[]]].to_a).to eq [3]
711
+ end
712
+ example "works with arrays of any depth" do
713
+ expect(dimensions[[[[[1,2]]]]]).to be_a Enumerator
714
+ expect(dimensions[[[[[1,2]]]]].to_a).to eq [1,1,1,2]
715
+ end
716
+ example "give dimensions only down to level 2" do
717
+ expect(dimensions[[[[[1,2]]]], 2]).to be_a Enumerator
718
+ expect(dimensions[[[[[1,2]]]], 2].to_a).to eq [1,1]
719
+ end
720
+
721
+ end
722
+
723
+ describe "Properties & Relations" do
724
+
725
+ example "???" do
726
+ expect(dimensions[table[->(*){ 0 }, 2,1,4,3]]).to be_a Enumerator
727
+ expect(dimensions[table[->(*){ 0 }, 2,1,4,3]].to_a).to eq [2,1,4,3]
728
+ end
729
+
730
+ end
731
+
732
+ end
733
+
734
+ end
735
+
696
736
  # TODO http://reference.wolfram.com/language/guide/RearrangingAndRestructuringLists.html
697
737
  # TODO http://reference.wolfram.com/language/guide/MathematicalAndCountingOperationsOnLists.html
698
738
 
@@ -706,13 +746,15 @@ describe MLL do
706
746
 
707
747
  # TODO move #nest_list and #fold_list and others here?
708
748
 
749
+ # TODO examples in README.rb
750
+
709
751
  # http://reference.wolfram.com/language/ref/Nest.html
710
752
  describe "#nest" do
711
753
 
712
754
  describe "Basic Examples:" do
713
755
 
714
756
  example "the function to nest can be a pure function" do
715
- expect(nest[->(i){ (1+i)**2 }, 1, 3]).to eq 676
757
+ expect(nest[1, 3, ->(i){ (1+i)**2 }]).to eq 676
716
758
  end
717
759
 
718
760
  end
@@ -720,7 +762,7 @@ describe MLL do
720
762
  describe "Scope:" do
721
763
 
722
764
  example "nesting can return a single number" do
723
- skip "#sqrt is yet to be implemented"
765
+ skip "#sqrt is yet to be implemented" # maybe use Array#zip instead?
724
766
  end
725
767
 
726
768
  end
@@ -739,12 +781,67 @@ describe MLL do
739
781
  describe "Properties & Relations:" do
740
782
 
741
783
  example "Ruby#inject automatically inserts second arguments from a list" do
742
- expect(nest[->(i){ i*2 }, 3, 4]).to eq ([2]*4).inject(3){ |i,j| i*j }
784
+ expect(nest[3, 4, ->(i){ i*2 }]).to eq ([2]*4).inject(3){ |i,j| i*j }
743
785
  end
744
786
 
745
787
  end
746
788
 
747
- # TODO neat graphic examples
789
+ end
790
+
791
+ # http://reference.wolfram.com/language/ref/NestWhile.html
792
+ describe "#nest_while" do
793
+
794
+ describe "Details:" do
795
+ # TODO a lot
796
+ end
797
+
798
+ describe "Basic Examples:" do
799
+
800
+ example "keep dividing by 2 until the result is no longer an even number" do
801
+ expect(nest_while[123456, ->(i){ i / 2 }, ->(i){ i.even? }]).to eq 1929
802
+ end
803
+
804
+ end
805
+
806
+ describe "Scope:" do
807
+
808
+ # TODO "always compare all values generated" do
809
+ # TODO "compare the last two values generated" do
810
+ # TODO "start comparisons after 4 iterations, and compare using the 4 last values" do
811
+ # TODO "start comparisons after 4 iterations, and compare using the 6 last values" do
812
+ # TODO example "stop after at most 4 iterations, even if the test is still true" do
813
+ # expect(nest_while[123456, 1, 4, ->(i){ i / 2 }, ->(i){ i.even? }]).to eq 7716
814
+ # end
815
+
816
+ end
817
+
818
+ describe "Generalizations & Extensions:" do
819
+
820
+ # TODO "return the last value for which the condition was still true" do
821
+
822
+ end
823
+
824
+ describe "Applications:" do
825
+
826
+ example "find the next prime after 888" do
827
+ require "prime"
828
+ expect(nest_while[888, ->(i){ i+1 }, ->(i){ !i.prime? }]).to eq 907
829
+ end
830
+ # TODO example "find the next twin prime after 888" do
831
+ # require "prime"
832
+ # expect(nest_while[888, 3, ->(i){ i+1 }, ->(i,_,k){ !i.prime? || !k.prime? }]).to eq 1021
833
+ # end
834
+
835
+ end
836
+
837
+ describe "Properties & Relations:" do
838
+
839
+ example "#fixed_point always compares the last two values" do
840
+ skip "#fixed_point is yet to be implemented"
841
+ end
842
+ # TODO "#nest_while can be expressed in terms of a while loop" do
843
+
844
+ end
748
845
 
749
846
  end
750
847
 
@@ -799,6 +896,39 @@ describe MLL do
799
896
 
800
897
  end
801
898
 
899
+ # http://reference.wolfram.com/language/ref/Mean.html
900
+ describe "#mean" do
901
+
902
+ describe "Basic Examples" do
903
+
904
+ example "mean of numeric values" do
905
+ expect(mean[[1.21, 3.4, 2.15, 4, 1.55]]).to eq 2.462
906
+ end
907
+ example "means of elements in each column" do
908
+ expect(mean[[[1, 2], [3, 4], [5, 6]]]).to be_a Enumerator
909
+ expect(mean[[[1, 2], [3, 4], [8, 9]]].to_a).to eq [4, 5]
910
+ end
911
+
912
+ end
913
+
914
+ describe "Applications" do
915
+
916
+ example "a 90-day moving mean" do
917
+ skip "#moving_map is yet to be implemented"
918
+ end
919
+
920
+ end
921
+
922
+ describe "Properties & Relations" do
923
+
924
+ example "#moving_average is a sequence of means" do
925
+ skip "#moving_average is yet to be implemented"
926
+ end
927
+
928
+ end
929
+
930
+ end
931
+
802
932
  end
803
933
 
804
934
  end
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.2.0
4
+ version: 2.1.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-07-11 00:00:00.000000000 Z
11
+ date: 2015-07-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler