lambda-calculus 0.1.0 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
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