lambda-calculus 0.1.0 → 0.1.4

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.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- ZGZmYzJlZTA5MjY5ZGViOTEzY2VhZGI4NGE0OWMxNTRlM2U1NTc5YQ==
4
+ Y2FlZmU1ZmMwMDMwOWUyYmYyOWYyN2M5YzQ4NzM3MTliMDA4NjExZg==
5
5
  data.tar.gz: !binary |-
6
- ZTlmMzZiNzk1MDk4YjNmZWY5NjhkYTRmMGM3OWJmMzJjNDY2ZGI3YQ==
6
+ YjQwZTU5MWFhZWU4NzM1ZmZjODI2YmJiYWY5Nzg0MmMyZGRmNjY2Zg==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- MWI5MzM2MGYwNjRkMWI3Zjc1ODNmNjFhNGM1Zjc0YmQwZmE3ZDRjY2EwMGQ4
10
- MmNhZWVhM2MzYTQzNGQxNDdjMjVlOTc5OTI2ZmJhYjcwZWU2MGU5MDgwNDg2
11
- ZTdjOGI1NTNlNzU0MzNkOGVlZjRjZjAwN2I0ZDcxMGNkMDExZjg=
9
+ OWRhYTFiYzBmODg5YWFlYTYyYTM1MTM3ZTViYjAwNjBmNDUwNGYwYTM4NmJl
10
+ NmE4YTE0NTUzNzc2MTRhMzdmOTk0YjY2ZDhlNDZhYmJlOTk2OWEyZDI1MDYw
11
+ YWJkNGQzMTFhODU1NWVmYzU1OThmNDE5MDE5OWJlMGU4YjM1ODI=
12
12
  data.tar.gz: !binary |-
13
- MGZiY2U3MjEyYzRmZWRmMjA4NWUxMDY4NDhjYjlmYWE0YTMzYzNiOGY4MWEy
14
- ODI2MDNiOGI5M2JjZDljNDk1NGM2YjU0ODU0NWYwMDRjMzNkNmJlOTE4ZmQ3
15
- MzkxN2JlNmU1ZmM3MDM0NTYzYWUyZTU2OWY3NDI3ZDRjNWFkMmY=
13
+ NDRlODAwM2NhYTA0ZjNlYTgyOTkwODg0NWRiODg2Nzk0ZTY2ODI3ZDlhNzk5
14
+ NzY3YjIxNmQyOGIxZTIxZWM1ZjdkMWZkZTY0MzAxYmY4NjJiYmYyNzNhNTkx
15
+ ZTIyNWIxODFhN2QwMzA5YWY4ZGU2NTQ3MDk3MGYwMjQ1Yjc1NGQ=
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2013 Alex Altair
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,68 @@
1
+ Lambda calculus engine [![Gem Version](https://badge.fury.io/rb/lambda-calculus.png)](http://badge.fury.io/rb/lambda-calculus)
2
+ ======================
3
+
4
+ Ever wanted to evaluate lambda expressions from the command line? Well now you can!
5
+ 1. Download this gem; `gem install lambda-calculus`.
6
+ 2. Open up pry or irb and type `require 'lambda-calculus'`.
7
+ 3. Declare a lambda expression; `my_exp = LambdaExpression.new('(\x.xy)(\a.a)')`
8
+ 4. Evaluate or beta reduce!
9
+ ```
10
+ > my_exp.beta_reduce
11
+ => (\a.a)y
12
+ > my_exp.evaluate
13
+ => y
14
+ ```
15
+ Lambda expressions are a class. Their attributes depend on which kind they are, as defined by the following code snippet from lambda-calculus.rb;
16
+
17
+ ```ruby
18
+ case args.length
19
+ when 1
20
+ @kind = :variable
21
+ @value = node_value
22
+ when 2
23
+ @kind = :abstraction
24
+ @bound_var = node_value
25
+ @body = child1
26
+ when 3
27
+ @kind = :application
28
+ @function = child1
29
+ @argument = child2
30
+ ```
31
+ Arguments
32
+ ---------
33
+ `LambdaExpression.new()` has two modes for taking arguments; natively or naturally. I tried to make it as flexible as possible while matching expectations.
34
+
35
+ Natively it can take one, two or three arguments where one makes it a variable, two makes it an abstraction, and three makes it an application. In each case the first argument must be a symbol or string of the correct form; anything but * for variables and abstractions, and only * for applications. The other arguments can be LambdaExpressions, strings of the natural form, or symbols.
36
+
37
+ Naturally, one can just give the lambda expression written as a string, the way you might write an expression to someone over text.
38
+
39
+ Some valid examples are shown below;
40
+
41
+ This will become a variable;
42
+ ```ruby
43
+ LambdaExpression.new(:x)
44
+ LambdaExpression.new('x')
45
+ ```
46
+ These will become abstractions;
47
+ ```ruby
48
+ LambdaExpression.new(:x, :x)
49
+ LambdaExpression.new('x', 'x')
50
+ LambdaExpression.new(:x, 'xy')
51
+ ```
52
+ These will become applications;
53
+ ```ruby
54
+ LambdaExpression.new(:*, :x, :y)
55
+ LambdaExpression.new('*', 'x', 'y')
56
+ LambdaExpression.new(:*, :x, '\a.bb')
57
+ ```
58
+ These will be parsed as strings
59
+ ```ruby
60
+ LambdaExpression.new('x')
61
+ LambdaExpression.new('xy')
62
+ LambdaExpression.new('(\x.xy)(\a.bb)')
63
+ LambdaExpression.new('\x.xy')
64
+ ```
65
+
66
+ Being able to accept arbitrary strings means that a string parser is included.
67
+ The method `beta_reduce` will perform beta reduction, but only on the top-level application.
68
+ Methods for printing facts about lambda expressions are also included; `lambda_string_tester` for strings, and `lambda_tester` for native LambdaExpression objects.
@@ -0,0 +1,11 @@
1
+ require 'rspec'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :test => :spec
7
+
8
+ desc "Run specs as default activity."
9
+ task :default => :spec
10
+ # Check the RDoc for RakeTask for various options that you can optionally pass into the task definition.
11
+ # https://github.com/rspec/rspec-core/blob/master/lib/rspec/core/rake_task.rb
@@ -0,0 +1,15 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = 'lambda-calculus'
3
+ spec.version = '0.1.4'
4
+ spec.date = Time.now.strftime("%Y-%m-%d")
5
+ spec.summary = "A class with methods for creating and evaluating lambda expressions."
6
+ spec.description = "This gem allows users to create and evaluate lambda expression objects from natural string input like '(\\x.xy)(\\a.aba)'."
7
+ spec.authors = ["Alex Altair"]
8
+ spec.email = 'alexanderaltair@gmail.com'
9
+ spec.files = `git ls-files`.split("\n") - %w(.rvmrc .gitignore)
10
+ spec.homepage = 'https://github.com/alexaltair/lambda-calculus'
11
+ spec.license = 'MIT'
12
+ spec.test_files = `git ls-files -- spec/*`.split("\n")
13
+ spec.post_install_message = "* Check out the documentation at #{spec.homepage} *"
14
+ spec.add_development_dependency "rspec"
15
+ end
@@ -1,9 +1,8 @@
1
- # Takes a string and find the index of the matching close paren to the open paren specified. Default open paren index is the beginning of the string.
1
+ # Takes a string and finds the index of the matching close paren to the open paren specified.
2
2
  def close_paren_index(string, open_paren_index = 0)
3
3
  if open_paren_index == 0
4
4
  raise ArgumentError "First character not an open paren." unless string[open_paren_index] == '('
5
- else
6
- raise ArgumentError "Given index not an open paren." unless string[open_paren_index] == '('
5
+ else raise ArgumentError "Given index not an open paren." unless string[open_paren_index] == '('
7
6
  end
8
7
  array = string.split('')
9
8
  depth = 1
@@ -22,16 +21,37 @@ end
22
21
 
23
22
  class LambdaExpression
24
23
 
25
- # Change the setters so that attributes cannot be changed to make a meaningless lambda expression.
24
+ # ----- Change the setters so that attributes cannot be changed to make a meaningless lambda expression.
26
25
  attr_accessor :kind, :value, :bound_var, :body, :function, :argument
26
+ # ----- Make a class variable or something, which stores all the strategies; LambdaExpression.strategies = [:eager, :lazy, :depth_first ... ]
27
27
 
28
28
  def initialize(*args)
29
+ # This deals with all possible types of arguments that could be given.
30
+ args = sanitize_args(*args)
31
+ node_value, child1, child2 = args
29
32
 
30
- # The first half of this deals with all possible types of arguments that could be given.
33
+ # At this point the first argument should be a symbol, and the rest LambdaExpressions.
34
+ case args.length
35
+ when 1
36
+ @kind = :variable
37
+ @value = node_value
38
+ when 2
39
+ @kind = :abstraction
40
+ @bound_var = node_value
41
+ @body = child1
42
+ when 3
43
+ @kind = :application
44
+ @function = child1
45
+ @argument = child2
46
+ else raise ArgumentError, "Wrong number of arguments. (Should be caught earlier.)"
47
+ end
48
+
49
+ end
31
50
 
51
+ def sanitize_args(*args)
32
52
  args.compact!
33
53
 
34
- # If the expression is initialized in natural mode, as a written-out string, the initializer passes that string to .string_to_lambda_args to turn it into the native arguments.
54
+ # If the expression is initialized in natural mode, as a written-out string, the sanitizer passes that string to .string_to_lambda_args to turn it into the native arguments.
35
55
  if args.length == 1 && args[0].is_a?(String)
36
56
  args = LambdaExpression.string_to_lambda_args(args[0])
37
57
  end
@@ -42,7 +62,7 @@ class LambdaExpression
42
62
  end
43
63
 
44
64
  if node_value.is_a?(String)
45
- node_value.to_sym
65
+ node_value = node_value.to_sym
46
66
  end
47
67
 
48
68
  if node_value.is_a?(Symbol)
@@ -58,40 +78,24 @@ class LambdaExpression
58
78
  else raise ArgumentError, "First argument is not a symbol."
59
79
  end
60
80
 
61
- # At this point the first argument should be a symbol, and the rest LambdaExpressions.
62
-
63
- case args.length
64
- when 1
65
- @kind = :variable
66
- @value = node_value
67
- when 2
68
- @kind = :abstraction
69
- @bound_var = node_value
70
- @body = child1
71
- when 3
72
- @kind = :application
73
- @function = child1
74
- @argument = child2
75
- else raise ArgumentError, "Wrong number of arguments. (Should be caught earlier.)"
76
- end
77
-
81
+ return *[node_value, child1, child2].compact
78
82
  end
79
83
 
80
-
81
- def to_s
82
- case self.kind
83
- when :variable then self.value.to_s
84
- when :abstraction then "\\#{self.bound_var}.#{self.body}"
85
- when :application
86
- function_string = "#{self.function}"
87
- argument_string = "#{self.argument}"
88
- if self.function.kind == :abstraction
89
- function_string = "(" + function_string + ")"
84
+ def self.string_to_lambda_args(string)
85
+ array = group_by_parens(string)
86
+ if array.length == 1
87
+ string = array[0]
88
+ if string[0] == '\\'
89
+ return string[1].to_sym, string[3..-1]
90
+ else return string.to_sym # Symbols are required to be only one character; this is enforced later in the initializer.
90
91
  end
91
- unless self.argument.kind == :variable
92
- argument_string = "(" + argument_string + ")"
92
+ else
93
+ last = array.pop
94
+ array.map! { |element| LambdaExpression.new(element) }
95
+ penultimate = array.inject do |function, next_arg|
96
+ LambdaExpression.new(:*, function, next_arg)
93
97
  end
94
- return function_string + argument_string
98
+ return :*, penultimate, last
95
99
  end
96
100
  end
97
101
 
@@ -115,25 +119,26 @@ class LambdaExpression
115
119
  array
116
120
  end
117
121
 
118
- def self.string_to_lambda_args(string)
119
- array = group_by_parens(string)
120
- if array.length == 1
121
- string = array[0]
122
- if string[0] == '\\'
123
- return string[1].to_sym, string[3..-1]
124
- else return string.to_sym # Symbols are required to be only one character; this is enforced later in the initializer.
122
+ def to_s
123
+ case self.instance_variable_get(:@kind)
124
+ when :variable then self.value.to_s
125
+ when :abstraction then "\\#{self.bound_var}.#{self.body}"
126
+ when :application
127
+ function_string = "#{self.function}"
128
+ argument_string = "#{self.argument}"
129
+ if self.function.kind == :abstraction
130
+ function_string = "(" + function_string + ")"
125
131
  end
126
- else
127
- last = array.pop
128
- array.map! { |element| LambdaExpression.new(element) }
129
- penultimate = array.inject do |function, next_arg|
130
- LambdaExpression.new(:*, function, next_arg)
132
+ unless self.argument.kind == :variable
133
+ argument_string = "(" + argument_string + ")"
131
134
  end
132
- return :*, penultimate, last
135
+ return function_string + argument_string
136
+ else raise "Lambda expression has no kind."
133
137
  end
134
138
  end
135
139
 
136
140
  # I stole this from the iternet, but understand how it works and tested it.
141
+ # ----- Change this so that it doesn't have any new instance variables.
137
142
  def deep_clone
138
143
  return @deep_cloning_obj if @deep_cloning
139
144
  @deep_cloning_obj = clone
@@ -154,12 +159,34 @@ class LambdaExpression
154
159
  deep_cloning_obj
155
160
  end
156
161
 
157
- # This method does beta reduction only at the top level. Fuller lambda experession evaluation is done by evaluate.
162
+ # Deep equality; tests whether LambdaExpressions are the same down to the value of the instance variables.
163
+ def ===(other)
164
+ return true if self == other
165
+ if self.kind == other.kind
166
+ case self.kind
167
+ when :variable
168
+ return self.value == other.value
169
+ when :abstraction
170
+ return (self.bound_var == other.bound_var &&
171
+ self.body === other.body)
172
+ when :application
173
+ return (self.function === other.function &&
174
+ self.argument === other.argument)
175
+ end
176
+ end
177
+ return false
178
+ end
179
+
180
+ # After de Bruijn indices are implemented, this will be the same as deep equality.
181
+ def alpha_equal?(other)
182
+ end
183
+
184
+ # This method does beta reduction only at the top level. Fuller lambda expression evaluation is done by #evaluate.
158
185
  def beta_reduce
159
- copy = self.deep_clone
160
- unless (copy.kind == :application) && (copy.function.kind == :abstraction)
161
- return copy
186
+ unless (self.kind == :application) && (self.function.kind == :abstraction)
187
+ return self
162
188
  end
189
+ copy = self.deep_clone
163
190
  replacement = copy.argument
164
191
  bound_variable = copy.function.bound_var
165
192
 
@@ -178,30 +205,51 @@ class LambdaExpression
178
205
  self.function = self.function.substitute(bound_variable, replacement)
179
206
  self.argument = self.argument.substitute(bound_variable, replacement)
180
207
  return self
181
- else raise ArgumentError, "First argument is not a LambdaExpression or has no .kind."
208
+ else raise ArgumentError, "First argument is not a LambdaExpression or has no kind."
182
209
  end
183
210
  end
184
211
 
185
212
  copy.function.body.substitute(bound_variable, replacement)
186
213
  end
187
214
 
188
- def evaluate(strategy=:lazy)
189
- raise "Method not yet written."
215
+ def evaluate(strategy=:depth_first)
216
+ case strategy
217
+ when :depth_first then self.evaluate_depth_first
218
+ else raise ArgumentError, "Argument #{strategy} is not an evaluation strategy."
219
+ end
220
+ # Eager/strict, pre-order, in-order, post-order/applicative-order, breadth-first, unstoppable hybrid
221
+ end
222
+
223
+ def evaluate_depth_first
224
+ expression = self.deep_clone
225
+ case expression.kind
226
+ when :variable then return expression
227
+ when :abstraction then return LambdaExpression.new( expression.bound_var, expression.body.evaluate_depth_first )
228
+ when :application
229
+ expression.function = expression.function.evaluate_depth_first
230
+ if expression.function.kind == :abstraction
231
+ return expression.beta_reduce.evaluate_depth_first
232
+ else
233
+ expression.argument = expression.argument.evaluate_depth_first
234
+ return expression
235
+ end
236
+ else raise ArgumentError, "This lambda expression has a wrong kind."
237
+ end
190
238
  end
191
239
 
192
240
  # This method helps me test LambdaExpression objects.
193
241
  def lambda_tester
194
- puts "To string: #{self}"
195
- puts "kind: #{self.kind}"
242
+ puts "To string: #{self}"
243
+ puts "kind: #{self.kind}"
196
244
  case self.kind
197
245
  when :variable
198
- puts "value: #{self.value}"
246
+ puts "value: #{self.value}"
199
247
  when :abstraction
200
- puts "bound_var: #{self.bound_var}"
201
- puts "body: #{self.body}"
248
+ puts "bound_var: #{self.bound_var}"
249
+ puts "body: #{self.body}"
202
250
  when :application
203
- puts "function: #{self.function}"
204
- puts "argument: #{self.argument}"
251
+ puts "function: #{self.function}"
252
+ puts "argument: #{self.argument}"
205
253
  end
206
254
  end
207
255
 
@@ -210,28 +258,27 @@ class LambdaExpression
210
258
  puts "Test string: #{string}"
211
259
  puts "Paren grouping: #{LambdaExpression.group_by_parens(string)}"
212
260
  args = LambdaExpression.string_to_lambda_args(string)
213
- arg0, arg1, arg2 = args
214
261
  puts "Lambda arguments: #{args}"
215
- thing = LambdaExpression.new(arg0, arg1, arg2)
262
+ thing = LambdaExpression.new(*args)
216
263
  thing.lambda_tester
217
264
  end
218
265
 
219
266
  # Runs a block on every leaf in the tree.
220
267
  def each_leaf!
221
- raise 'Method not yet written.'
268
+ raise "Method not yet written."
222
269
 
223
270
  self.each do |leaf|
224
271
  yield(leaf)
225
272
  end
226
273
  end
227
274
 
275
+ def evaluates_to?(other, strategy=:depth_first)
276
+ self.evaluate(strategy) === other
277
+ end
278
+
228
279
  # Returns a random LambdaExpression
229
280
  def self.random
230
281
  raise "Method not yet written."
231
282
  end
232
283
 
233
284
  end
234
-
235
- # LambdaExpression.lambda_string_tester('(\x.yx)\a.bb')
236
- # p test.beta_reduce
237
- # p test
@@ -0,0 +1,143 @@
1
+ require 'spec_helper'
2
+
3
+ describe LambdaExpression do
4
+
5
+ describe 'new' do
6
+
7
+ it "should fail to initizlie the empty string" do
8
+ expect { LambdaExpression.new('') }.to raise_error
9
+ end
10
+
11
+ it "should initialize single characters as variables" do
12
+ test_cases = ['x', :a, 'g', :l, 'y', 'z']
13
+ test_cases.each do |expression|
14
+ LambdaExpression.new(expression).kind.should == :variable
15
+ end
16
+ end
17
+
18
+ it "should initialize abstractions" do
19
+ test_cases = [[:x, :x] , [:a, 'xa'], ['g', 'ga'], ['x', :x], ['\x.x'], ['\x.\y.xy']]
20
+ test_cases.each do |expression|
21
+ LambdaExpression.new(*expression).kind.should == :abstraction
22
+ end
23
+ end
24
+
25
+ it "should initialize applications" do
26
+ test_cases = [[:*, :x, :x], ['*', :a, 'x'], ['*', 'g', 'a'], ['xx'], ['a\x.\y.xy']]
27
+ test_cases.each do |expression|
28
+ LambdaExpression.new(*expression).kind.should == :application
29
+ end
30
+ end
31
+
32
+ it "should reject * as an argument in all other cases" do
33
+ test_cases = [[:*], [:*, :*], [:*, '*'], ['*', '*'], ['*', :*], ['x', :*], [:x, :*], [:x, '*'], ['x', '*'], ['*', '*', 'x'], ['*', 'x', '*'], [:*, :*, :x], ['a', '*', '*']]
34
+ test_cases.each do |expression|
35
+ expect { LambdaExpression.new(*expression) }.to raise_error
36
+ end
37
+ end
38
+
39
+ end
40
+
41
+ describe 'beta_reduce' do
42
+
43
+ it "should return the same object if it can't reduce" do
44
+ example = LambdaExpression.new('x')
45
+ example.beta_reduce.should == example
46
+ example.beta_reduce.value.should == example.value # Dubious meaning.
47
+
48
+ test_cases = ['\x.x', 'xy', 'x\y.y', 'xyz', '(\a.aab)xy']
49
+ test_cases.each do |expression|
50
+ example = LambdaExpression.new(expression)
51
+ example.beta_reduce.should == example
52
+ end
53
+ end
54
+
55
+ it "should return a different object if it can perform beta reduction" do
56
+ test_cases = ['(\x.xx)(\y.yy)', '(\x.xx)(\x.xx)', '(\x.yx)a', '(\a.aab)(xy)']
57
+ test_cases.each do |expression|
58
+ example = LambdaExpression.new(expression)
59
+ example.beta_reduce.should_not == example
60
+ end
61
+ end
62
+
63
+ end
64
+
65
+ describe 'evaluate' do
66
+ it "should return the same object for expressions that can't be evaluated"
67
+
68
+ # I have no idea how to correctly implement this.
69
+ # it "should return with any strategy for expressions with finite reduction steps" do
70
+ # test_cases = ['x', 'xy'] # Come up with complicated examples.
71
+ # test_cases.each do |string|
72
+ # expression = LambdaExpression.new(string)
73
+ # LambdaExpression.strategies.each do |strategy|
74
+ # expression.evaluate(strategy).should # ... should what?
75
+ # end
76
+ # end
77
+ # end
78
+ end
79
+
80
+ describe '===' do
81
+
82
+ it "should return true when same up to same variable names, false otherwise" do
83
+ test_cases = { 'x'=>'x', :x=>'x', 'xy'=>'xy', '\a.ba'=>'\a.ba', '(\x.yx)a'=>'(\x.yx)a' }
84
+ test_cases.each do |expression|
85
+ example_self, example_other = LambdaExpression.new(expression[0]), LambdaExpression.new(expression[1])
86
+ example_self.should === example_other
87
+ end
88
+
89
+ test_cases = { 'x'=>'y', :x=>'y', 'xy'=>'yx', '\b.ba'=>'\a.ab', '(\x.yx)b'=>'(\x.yx)a' }
90
+ test_cases.each do |expression|
91
+ example_self, example_other = LambdaExpression.new(expression[0]), LambdaExpression.new(expression[1])
92
+ example_self.should_not === example_other
93
+ end
94
+ end
95
+
96
+ it "should be reflexive" do
97
+ test_cases = ['x', :x, 'xy', '\a.ba', '(\x.yx)a']
98
+ test_cases.each do |expression|
99
+ example = LambdaExpression.new(expression)
100
+ example.should === example
101
+ end
102
+ end
103
+
104
+ it "should be symmetrical" do
105
+ test_cases = { 'x'=>'x', :x=>'x', 'xy'=>'xy', '\a.ba'=>'\a.ba', '(\x.yx)a'=>'(\x.yx)a', 'x'=>'y', :x=>'y', 'xy'=>'yx', '\b.ba'=>'\a.ab', '(\x.yx)b'=>'(\x.yx)a' }
106
+ test_cases.each do |expression|
107
+ example_self, example_other = LambdaExpression.new(expression[0]), LambdaExpression.new(expression[1])
108
+ (example_self === example_other).should == (example_other === example_self)
109
+ end
110
+ end
111
+
112
+ # Later, too hard.
113
+ # it "should be transitive" do
114
+ # end
115
+
116
+ # pending "write a pending message"
117
+
118
+ end
119
+
120
+ describe 'deep_clone' do
121
+ it "should copy complex expressions which are alpha_equal and === but not =="
122
+ it "should leave the self untouched"
123
+ end
124
+
125
+ describe 'alpha_equal?' do
126
+ it "should return true for expressions with the same structure but different variable names"
127
+ end
128
+
129
+
130
+
131
+ # Can I write a function, has_lambda_properties?, to use in this file?
132
+ # Edge cases
133
+ # The base cases create objects with correct properties
134
+ # Make complex specific LambdaExpressions and make sure they were initialized correctly
135
+ # Beta reduce leaves self untouched
136
+ # RSpec with random lambdas
137
+
138
+ end
139
+
140
+ # test_cases = [blah]
141
+ # test_cases.each do |expression|
142
+ # # code
143
+ # end
@@ -0,0 +1,9 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require './lib/lambda-calculus.rb'
5
+
6
+ # RSpec.configure do |config|
7
+ # config.color_enabled = true
8
+ # config.formatter = 'documentation'
9
+ # end
metadata CHANGED
@@ -1,27 +1,51 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lambda-calculus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Altair
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-07-21 00:00:00.000000000 Z
12
- dependencies: []
13
- description: This gem allows users to create lambda expression objects in Ruby from
14
- natural string input like '(\x.xy)(\a.aba)'.
11
+ date: 2013-10-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ! '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ! '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: This gem allows users to create and evaluate lambda expression objects
28
+ from natural string input like '(\x.xy)(\a.aba)'.
15
29
  email: alexanderaltair@gmail.com
16
30
  executables: []
17
31
  extensions: []
18
32
  extra_rdoc_files: []
19
33
  files:
34
+ - .rspec
35
+ - Gemfile
36
+ - LICENSE.txt
37
+ - README.md
38
+ - Rakefile
39
+ - lambda-calculus.gemspec
20
40
  - lib/lambda-calculus.rb
41
+ - spec/lambda_calculus_spec.rb
42
+ - spec/spec_helper.rb
21
43
  homepage: https://github.com/alexaltair/lambda-calculus
22
- licenses: []
44
+ licenses:
45
+ - MIT
23
46
  metadata: {}
24
- post_install_message:
47
+ post_install_message: ! '* Check out the documentation at https://github.com/alexaltair/lambda-calculus
48
+ *'
25
49
  rdoc_options: []
26
50
  require_paths:
27
51
  - lib
@@ -41,4 +65,6 @@ rubygems_version: 2.0.5
41
65
  signing_key:
42
66
  specification_version: 4
43
67
  summary: A class with methods for creating and evaluating lambda expressions.
44
- test_files: []
68
+ test_files:
69
+ - spec/lambda_calculus_spec.rb
70
+ - spec/spec_helper.rb