我自己的lisp,也来实现个匿名递归函数玩玩,嘿!(2)

最近给我的lisp修正了一下,把原本很简陋的宏系统(使用eval函数执行列表,列表可以实时生成)扩展了一下,并且让宏可以像函数一样被使用,现在我们的lisp可以说是跨越了一大步了!

使用宏来试试吧:

(define
	'(recur p c)
	(define
		this
		(lambda p c)
	)
)
#我设定的define用途很多:
#	第一个参数为label,为定义变量
#	第一个参数是未保护的列表,则是定义函数
#	第一个参数是受保护的列表时,就是定义一个宏

使用时,如下:

(
	(recur (n) (if (< n 1) 0 (+ (this (- n 1)) n)))
	10
)
this就可以代表这个匿名函数了;这样的缺陷,是this放在了当前环境里;

如果当前环境又使用recur定义了一个别的匿名递归函数,原来的函数就被覆盖了;

所以我们使用lambda包含起来,制作一个内层环境:

(define
	'(recur p c)
	(lambda
		p
		(eval
			(cons
				(define this (lambda p c))
				(quote p)
			)
		)
	)
)
这样,this放在了lambda 内部,它的作用范围也局限在其内部,换句话说我们弄了个嵌套函数出来:

cons负责将一个元素加入到一个列表的头部,这里我们用来生成执行语句;

quote的用处是保护p,lambda接受的第一个列表参数是不用保护的,但cons第二个参数却必须保护起来,这是为了让cons可以接受一个实时生成的列表,但是这里我们要用quote保护p

cons和quote配合实时产生了一个执行语句,然后我们用eval执行它,总的使用一个lambda表示

于是我们就得到了一个不用担心this会被覆盖的recur宏,使用recur宏的方法和lambda无差别,但是却可以使用this代表匿名函数自身

但是这还不够,我们希望的是把this添加到lambda的功能里去,而不是增加一个recur宏

可如果我们直接把宏定义为lambda,就坏了,宏只是简单的符号替换功能,lambda被覆盖成宏的话,就相当于在宏内部调用宏自身,这首先就会破坏我们希望得到的结果了,更可能导致意想不到的错误

为了解决这个问题,我在lisp中引入了builtin函数,该函数的作用是查找同名的内部注册函数,因为内部注册函数是不能删除的,只可能被内层环境覆盖掉,builtin可以直接查找内部注册函数,因此可以避免同名变量的干扰;只要你不把builtin给覆盖掉,这种查找就有效:

(define
	lambda
	(define
		'(_ p c)
		((builtin lambda)
			p
			(eval
				(cons
					(define this ((builtin lambda) p c))
					(quote p)
				)
			)
		)
	)
)
我使用下划线,表示这个宏俺们不需要名字,因为之后俺就会把它赋给lambda标签(虽然这_可以正常使用)

(我的define会作一个定义,并且返回该定义,当然也可以用macro函数来定义宏)

现在,我们可以很幸福的这么用了:

(
	(lambda (n) (if (< n 1) 0 (+ (this (- n 1)) n)))
	10
)
虽然对于本身就专门实现了self关键字用于lambda的我的lisp来说,我根本不需要大费周章的弄这么一个宏,只需要这样:
(
	(lambda (n) (if (< n 1) 0 (+ (self (- n 1)) n)))
	10
)

转载于:https://my.oschina.net/liudiwu/blog/156462

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值