Download code - Download code Ruby

From LiteratePrograms
Jump to: navigation, search

Back to Lambda_Calculus_Interpreter_(Ruby)

Download for Windows: single file, zip

Download for UNIX: single file, zip, tar.gz, tar.bz2

lambda.rb

  1 # Copyright (c) 2012 the authors listed at the following URL, and/or
  2 # the authors of referenced articles or incorporated external code:
  3 # http://en.literateprograms.org/Lambda_Calculus_Interpreter_(Ruby)?action=history&offset=20070924114443
  4 # 
  5 # Permission is hereby granted, free of charge, to any person obtaining
  6 # a copy of this software and associated documentation files (the
  7 # "Software"), to deal in the Software without restriction, including
  8 # without limitation the rights to use, copy, modify, merge, publish,
  9 # distribute, sublicense, and/or sell copies of the Software, and to
 10 # permit persons to whom the Software is furnished to do so, subject to
 11 # the following conditions:
 12 # 
 13 # The above copyright notice and this permission notice shall be
 14 # included in all copies or substantial portions of the Software.
 15 # 
 16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 17 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 18 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 19 # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 20 # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 21 # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 22 # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 23 # 
 24 # Retrieved from: http://en.literateprograms.org/Lambda_Calculus_Interpreter_(Ruby)?oldid=10974
 25 
 26 class Var 
 27   def initialize(name)
 28     @name = name
 29   end
 30   
 31   def eval(env=Hash.new)
 32     # lookup the value of the variable in the environment
 33     env[@name] 
 34   end
 35   
 36   def to_s
 37     @name
 38   end
 39 end
 40 
 41 class BinaryOp
 42   def initialize(op, t1, t2)
 43     @op, @t1, @t2 = op, t1, t2
 44   end
 45   
 46   def eval(env=Hash.new)
 47     case @op
 48       when "+"   
 49         @t1.eval(env) + @t2.eval(env)
 50       when "*"   
 51         @t1.eval(env) * @t2.eval(env)
 52       when "and" 
 53         @t1.eval(env) and @t2.eval(env)
 54       when "or"  
 55         @t1.eval(env) or @t2.eval(env)
 56       else 
 57         raise "Unknown binary operation"
 58     end
 59   end
 60   
 61   def to_s
 62     "#{@t1} #{@op} #{@t2}"
 63   end
 64 end
 65 
 66 class UnaryOp 
 67   def initialize(op, t)
 68     @op, @t = op, t
 69   end
 70   
 71   def eval(env=Hash.new)
 72     case @op
 73       when "-"
 74         -(@t.eval(env))
 75       when "not"
 76         !(@t.eval(env))
 77       else 
 78         raise "Unknown unary operation"
 79       end
 80   end
 81   
 82   def to_s
 83     "#{@op} #{@t}"
 84   end
 85 end
 86 
 87 class Let
 88   def initialize(var, t1, t2)
 89     @var, @t1, @t2 = var, t1, t2
 90   end
 91   
 92   def eval(env=Hash.new)
 93     env[@var] = @t1.eval(env)
 94     @t2.eval(env) 
 95   end
 96   
 97   def to_s
 98     "let (#{@var} = #{@t1}) in (#{@t2})"
 99   end
100 end
101 
102 class Lambda
103   def initialize(var, term)
104     @var, @term = var, term
105   end
106   
107   def eval(env=Hash.new)
108     var, term = @var, @term
109     # returns a procedure that will perform
110     # the body of the lambda function
111     
112     proc = Proc.new { |t| 
113       env[var] = t    # substitution into body of function
114       term.eval(env)
115     }
116     
117     # add a to_s method to the newly created Proc
118     def proc.to_s 
119       "lambda"
120     end
121     
122     proc
123   end
124   
125   def to_s
126     "\\#{@var}.#{@term}"
127   end
128 end
129 
130 class Apply
131   def initialize(t1, t2)
132     @t1, @t2 = t1, t2
133   end
134 
135   def eval(env=Hash.new)
136     # the first term must evaluate to a ruby Proc
137     @t1.eval(env).call(@t2.eval(env))
138   end
139   
140   def to_s
141     "(#{@t1}) #{@t2}"
142   end
143 end
144 
145 class If
146   def initialize(t1, t2, t3)
147     @t1, @t2, @t3 = t1, t2, t3
148   end
149   
150   def eval(env=Hash.new)
151     if @t1.eval(env)
152       @t2.eval(env)
153     else
154       @t3.eval(env)
155     end
156   end
157   
158   def to_s
159     "if (#{@t1}) then #{@t2} else #{@t3}"
160   end
161 end
162 
163 module Eval
164   def eval(env=Nil)
165     self
166   end
167 end
168 
169 class Fixnum
170   include Eval
171 end
172 
173 class Bignum
174   include Eval
175 end
176 
177 class TrueClass
178   include Eval
179 end
180 
181 class FalseClass
182   include Eval
183 end
184 
185 term1 = BinaryOp.new("*", 99, 100)
186 
187 # the else clause contains a type error but won't be executed
188 term2 = If.new(BinaryOp.new("or", true, false), -10, UnaryOp.new("not", 99))
189 
190 term3 = Let.new("x", 25, BinaryOp.new("+", Var.new("x"), 50))
191 
192 double = Lambda.new("n", BinaryOp.new("+", Var.new("n"), Var.new("n")))
193 term4 = Apply.new(double, 12)
194 
195 # \x.\y. x + y
196 add = Lambda.new("x", Lambda.new("y", BinaryOp.new("+", Var.new("x"), Var.new("y"))))
197 
198 term5 = Let.new("a", add, Apply.new(Apply.new(Var.new("a"), 10), 9))
199 
200 badterm = BinaryOp.new("+", 50, false)
201 wierdterm = BinaryOp.new("+", Object.new, Object.new)
202 


Views
Personal tools