[Lua]50行代码的解释器,用来演示lambda calculus
嗯,来写写经过:
在知乎上看见用Belleve牛用javascript写了一个精简的lisp解释器
=>
我也想写一个,用lua写,能多简单呢?
=>
写了一个阉割的scheme解释器,包含lambda/if两个special form,以及+-=print几个过程,60行代码
=>
能再精简吗?比如把if给去掉?
=>
搜索,嗯,lambda calculus能帮我
=>
阅读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:
((lambda (zero one add mul pow sub1 true false and or)
((lambda (sub not zero? two Y)
((lambda (less-equal? equal? three four)
;------------------------------
((lambda (for-each fib)
(for-each (lambda (i) (print (fib zero one zero i))) zero (mul four four))
)
(Y
(lambda (self)
(lambda (f i n)
(f i)
(((equal? i n)
(lambda () i)
(lambda () (self f (add i one) n))))
)
))
(Y
(lambda (self)
(lambda (a b i n)
(((equal? i n)
(lambda () a)
(lambda () (self b (add a b) (add i one) n))))
)
))
)
;------------------------------
)
(lambda (m n) (zero? (sub m n)))
(lambda (m n) (and (zero? (sub m n)) (zero? (sub n m))))
(add two one)
(add two two)
))
(lambda (m n) (n sub1 m))
(lambda (a) (a false true))
(lambda (n) (n (lambda (x) false) true))
(add one one)
(lambda (f)
((lambda (g) (g g))
(lambda (g) (f (lambda (a) ((g g) a))))))
))
(lambda (f x) x)
(lambda (f x) (f x))
(lambda (m n f x) (m f (n f x)))
(lambda (m n f) (m (n f)))
(lambda (e b) (e b))
(lambda (n f x)
(((n
(lambda (g h) (h (g f))))
(lambda (u) x))
(lambda (u) u)))
(lambda (a b) a)
(lambda (a b) b)
(lambda (a b) (a b a))
(lambda (a b) (a a b))
)
lua解释器代码:
function S_parse(s)
s = string.gsub(s, ';[^\n]+\n', '')
s = string.gsub(s, '%s+', ',')
s = string.gsub(s, '[%(%)]', {['(']='{',[')']='}'})
s = string.gsub(s, '[^{},%d][^{},]*', '"%1"')
return assert(loadstring(string.format("return {%s}", s)))()[]
end
function S_lookupVar(vm, env, name)
while env do
if env[name] then return env[name] end
env = env[vm]
end
end
function S_createLambda(vm, env, argIdx, expArgs, expBody)
return function(arg)
local newEnv = {[vm]=env, [expArgs[argIdx]]=arg}
if argIdx == #expArgs then
for i = , #expBody - do S_interpret(vm, newEnv, expBody[i]) end
return S_interpret(vm, newEnv, expBody[#expBody])
else
return S_createLambda(vm, newEnv, argIdx + , expArgs, expBody)
end
end
end
function S_interpret(vm, env, exp)
if type(exp) == 'string' then
return S_lookupVar(vm, env, exp)
elseif exp[] == 'lambda' then
return S_createLambda(vm, env, , #exp[] > and exp[] or {'_'}, exp)
else
local p = S_interpret(vm, env, exp[])
for i = , math.max(#exp, ) do
p = p(exp[i] and S_interpret(vm, env, exp[i]) or nil)
end
return p
end
end
function S_createVM()
return {
G = {
['print'] = function(n) print(n(function(i) return i + end)()) end,
},
}
end
function S_eval(vm, s)
return S_interpret(vm, vm.G, S_parse(s))
end S_eval(S_createVM(), io.read('*a'))
驱动:
#! /bin/bash
cat script.rkt | lua main.lua
结果:
源码放这儿:https://github.com/PublicScan/LambdaCalculus/tree/c4a64b162b7049a6d278c86aaaa4a7c0750d7fa7
[Lua]50行代码的解释器,用来演示lambda calculus的更多相关文章
- python爬虫实战:利用scrapy,短短50行代码下载整站短视频
近日,有朋友向我求助一件小事儿,他在一个短视频app上看到一个好玩儿的段子,想下载下来,可死活找不到下载的方法.这忙我得帮,少不得就抓包分析了一下这个app,找到了视频的下载链接,帮他解决了这个小问题 ...
- 50行代码实现python计算器主要功能
实现功能:计算带有括号和四则运算的式子 3*( 4+ 50 )-(( 100 + 40 )*5/2- 3*2* 2/4+9)*((( 3 + 4)-4)-4) 基本思路:使用正则表达式提取出每一层 ...
- 50行代码实现缓存,JAVA内存模型原理
遇见这样的高人怎么办??下面是一个简单缓存的实现,相当牛叉!自己看吧,只有50行代码. 摘自:http://www.oschina.net/code/snippet_55577_3887 import ...
- HTML5游戏实战(1):50行代码实现正面跑酷游戏
前段时间看到一个"熊来了"的HTML5跑酷游戏,它是一个典型的正面2D跑酷游戏,这里借用它来介绍一下用Gamebuilder+CanTK开发正面跑酷游戏的基本方法. CanTK(C ...
- 50行代码实现GAN | 干货演练
2014年,Ian Goodfellow和他的同事发表了一篇论文,向世界介绍了生成对抗网络(GAN).通过对计算图和博弈论的创新性组合,他们表明如果有足够的建模能力,两个相互对抗的模型可以通过普通的反 ...
- 基于requirejs+bluebird,50行代码实现轻巧实用的前端CMD加载器
首先是github地址,可以用git克隆命令也可以直接在git页面下载 https://github.com/kazetotori/js-requireAsync 下载下来后目录结构是这样的 -pac ...
- OpenCV图像识别初探-50行代码教机器玩2D游戏【华为云技术分享】
版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/devcloud/article/detai ...
- 50行代码仿backbone_todos
<!doctype html> <html> <head> <meta charset="utf-8"> <title> ...
- 50行代码实现的高性能动画定时器 raf-interval
写在前面 raf-interval 是基于 window.requestAnimationFrame() 封装的定时器. Github: https://github.com/dntzhang/raf ...
随机推荐
- LVS三种模式配置及优点缺点比较
目录: LVS三种模式配置 LVS 三种工作模式的优缺点比较 LVS三种模式配置 LVS三种(LVS-DR,LVS-NAT,LVS-TUN)模式的简要配置 LVS是什么: http://www.lin ...
- 利用PHP执行SQL文件,将SQL文件导入到数据库
如何利用php自动执行.sql文件.其实很简单,就是获取sql文件中的内容,然后将每一句sql语句一次执行就行啦. 这是代码 //读取文件内容 $_sql = file_get_contents('t ...
- React Native填坑之旅--动画
动画是提高用户体验不可缺少的一个元素.恰如其分的动画可以让用户更明确的感知当前的操作是什么. 无疑在使用React Native开发应用的时候也需要动画.这就需要知道RN都给我们提供了那些动画,和每个 ...
- C# async await 学习笔记2
C# async await 学习笔记1(http://www.cnblogs.com/siso/p/3691059.html) 提到了ThreadId是一样的,突然想到在WinForm中,非UI线程 ...
- 待实验:Android 增量升级
参考资料: 增量升级(省流量更新)的Android客户端实现 http://blog.csdn.net/sgwhp/article/details/9009427 http://my.oschina ...
- Nginx代理与负载均衡配置与优化
Nginx代理 Nginx从0.7.48版本开始,支持了类似Squid的缓存功能.Nginx的Web缓存服务主要由proxy_cache相关指令集和fastcgi_cache相关指令集构成,前者用于反 ...
- 【基础知识】.Net基础加强08天
一. 文件的读取 1. 有FileStrem,为什么还要StreamWriter和StreamRead StreamWriter和StreamRead是用来读取文本文件的,每次只读取一行文本文件 二. ...
- Queue插入的时候报错:源数组长度不足。请检查 srcIndex 和长度以及数组的下限。
异常问题记录: 本想自己手动实现一个日志记录功能.使用Queue队列集合来实现多线程的日志记录. 测试 一个线程写入数据Enqueue和一个线程读取数据Dequeue ,直接用的无休眠死循环. 终于抛 ...
- kali Linux Web 渗透测试视频教程— 第六课 网络扫描-nmap与zmap
Kali Linux Web 渗透测试视频教程— 第六课 网络扫描-nmap与zmap 文/玄魂 目录 Kali Linux Web 渗透测试视频教程— 第六课 网络扫描-nmap与zmap. 1 N ...
- tomcat安全配置
1. 注释或删除 tomcat-users.xml 所有用户权限,看上去如下: <tomcat-users></tomcat-users> 2. 隐藏tomcat版本信息 1 ...