最近给我的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
)