嗯,來寫寫通過:javascript
在知乎上看見用Belleve牛用javascript寫了一個精簡的lisp解釋器 java
=>git
我也想寫一個,用lua寫,能多簡單呢? github
=>bash
寫了一個閹割的scheme解釋器,包含lambda/if兩個special form,以及+-=print幾個過程,60行代碼 less
=>lua
能再精簡嗎?好比把if給去掉? spa
=>code
搜索,嗯,lambda calculus能幫我 orm
=>
閱讀wiki上lambda calculus的"Encoding datatypes"部分
=>
改寫scheme腳本,用Y-combinator幫助實現遞歸,用church numeral表示數字,以及實現church numeral之上的基本邏輯、算數、關係運算,最後用這些基本運算編寫for-each和fib過程
=>
從解釋器裏移除關鍵字if,移除過程+-=,改寫print過程使之可以打印church numeral
=>
進一步把lambda實現爲單參數過程,多參數lambda的聲明和調用變成了語法糖,因而全部過程都是fully curried的了,和haskell同樣
=>
雖然scheme腳本爲了打印fibonacci數列須要作更多的事情,但解釋器僅僅爲這門閹割scheme提供了一個lambda關鍵字;就結果而言,它演示瞭如何在只支持「匿名過程」這個基本元素的語言中實現強大的計算能力;固然,完成這一切靠的是lambda calculus理論。過程和結果都很是有趣~
scheme代碼,只支持lambda這個special form和基本過程print:
1 ((lambda (zero one add mul pow sub1 true false and or) 2 ((lambda (sub not zero? two Y) 3 ((lambda (less-equal? equal? three four) 4 ;------------------------------ 5 ((lambda (for-each fib) 6 (for-each (lambda (i) (print (fib zero one zero i))) zero (mul four four)) 7 ) 8 (Y 9 (lambda (self) 10 (lambda (f i n) 11 (f i) 12 (((equal? i n) 13 (lambda () i) 14 (lambda () (self f (add i one) n)))) 15 ) 16 )) 17 (Y 18 (lambda (self) 19 (lambda (a b i n) 20 (((equal? i n) 21 (lambda () a) 22 (lambda () (self b (add a b) (add i one) n)))) 23 ) 24 )) 25 ) 26 ;------------------------------ 27 ) 28 (lambda (m n) (zero? (sub m n))) 29 (lambda (m n) (and (zero? (sub m n)) (zero? (sub n m)))) 30 (add two one) 31 (add two two) 32 )) 33 (lambda (m n) (n sub1 m)) 34 (lambda (a) (a false true)) 35 (lambda (n) (n (lambda (x) false) true)) 36 (add one one) 37 (lambda (f) 38 ((lambda (g) (g g)) 39 (lambda (g) (f (lambda (a) ((g g) a)))))) 40 )) 41 (lambda (f x) x) 42 (lambda (f x) (f x)) 43 (lambda (m n f x) (m f (n f x))) 44 (lambda (m n f) (m (n f))) 45 (lambda (e b) (e b)) 46 (lambda (n f x) 47 (((n 48 (lambda (g h) (h (g f)))) 49 (lambda (u) x)) 50 (lambda (u) u))) 51 (lambda (a b) a) 52 (lambda (a b) b) 53 (lambda (a b) (a b a)) 54 (lambda (a b) (a a b)) 55 )
lua解釋器代碼:
1 function S_parse(s) 2 s = string.gsub(s, ';[^\n]+\n', '') 3 s = string.gsub(s, '%s+', ',') 4 s = string.gsub(s, '[%(%)]', {['(']='{',[')']='}'}) 5 s = string.gsub(s, '[^{},%d][^{},]*', '"%1"') 6 return assert(loadstring(string.format("return {%s}", s)))()[1] 7 end 8 function S_lookupVar(vm, env, name) 9 while env do 10 if env[name] then return env[name] end 11 env = env[vm] 12 end 13 end 14 function S_createLambda(vm, env, argIdx, expArgs, expBody) 15 return function(arg) 16 local newEnv = {[vm]=env, [expArgs[argIdx]]=arg} 17 if argIdx == #expArgs then 18 for i = 3, #expBody - 1 do S_interpret(vm, newEnv, expBody[i]) end 19 return S_interpret(vm, newEnv, expBody[#expBody]) 20 else 21 return S_createLambda(vm, newEnv, argIdx + 1, expArgs, expBody) 22 end 23 end 24 end 25 function S_interpret(vm, env, exp) 26 if type(exp) == 'string' then 27 return S_lookupVar(vm, env, exp) 28 elseif exp[1] == 'lambda' then 29 return S_createLambda(vm, env, 1, #exp[2] > 0 and exp[2] or {'_'}, exp) 30 else 31 local p = S_interpret(vm, env, exp[1]) 32 for i = 2, math.max(#exp, 2) do 33 p = p(exp[i] and S_interpret(vm, env, exp[i]) or nil) 34 end 35 return p 36 end 37 end 38 function S_createVM() 39 return { 40 G = { 41 ['print'] = function(n) print(n(function(i) return i + 1 end)(0)) end, 42 }, 43 } 44 end 45 function S_eval(vm, s) 46 return S_interpret(vm, vm.G, S_parse(s)) 47 end 48 49 S_eval(S_createVM(), io.read('*a'))
驅動:
1 #! /bin/bash 2 cat script.rkt | lua main.lua
結果:
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
源碼放這兒:https://github.com/PublicScan/LambdaCalculus/tree/c4a64b162b7049a6d278c86aaaa4a7c0750d7fa7