我偶然发现了这个文章,解释在Y Combinator的。代码在 Scheme 中,但我正在尝试使用 Common Lisp 来解决它。
但是,我在将 Scheme 转换为 Common Lisp 时遇到了麻烦。Scheme 为函数和(其他)变量使用单一命名空间,但 Common Lisp 为函数和变量使用不同的命名空间。我怎样才能解决这个差异,以获得工作的 Common Lisp 代码?
这是教程中的一些 Scheme 代码。
一开始作者定义了阶乘函数:
(define (factorial n)
if (= n 0)
1
(* n (factorial (- n 1)))))
Run Code Online (Sandbox Code Playgroud)
并将其翻译成这样:
(define factorial
(lambda (n)
(if (= n 0)
1
(* n (factorial (- n 1))))))
Run Code Online (Sandbox Code Playgroud)
因为(根据作者的说法)这就是 Scheme 所做的:
Scheme 在评估它之前简单地将第一个定义转换为第二个定义。所以 Scheme 中的所有函数都是真正的 lambda 表达式。
我尝试在 Common Lisp 中重写上述两个片段,以模仿从第一种形式到第二种形式的转换。但是defineCL 中没有,也没有单个名称空间。所以我试图欺骗我的方式。
在 Common Lisp 中重写第一个 Scheme …
我有点新的CL和目前正在设法绕到我的头mapcan,#',funcall和关闭.这是一个闭包,它将一个谓词应用于数字n,如果正确,则返回(list n),否则nil:
(defun all-those (predicate)
(lambda (n)
(if (funcall predicate n) (list n))))
Run Code Online (Sandbox Code Playgroud)
我知道我需要调用funcall将此闭包转换为函数.这很好用:
> (funcall (all-those #'evenp) 8)
(8)
Run Code Online (Sandbox Code Playgroud)
现在我尝试将以后创建的函数作为参数传递给mapcan:
> (mapcan #'(funcall (all-those #'evenp)) '(1 2 3 4))
Run Code Online (Sandbox Code Playgroud)
我得到一个编译时错误: (FUNCALL (ALL-THOSE #'EVENP)) is not a legal function name.
但是如果我省略#'也可以funcall:
> (mapcan (all-those #'evenp) '(1 2 3 4))
(2 4)
Run Code Online (Sandbox Code Playgroud)
现在我很困惑.我的理解是,当使用mapcan跟随符号的函数绑定(*)时我需要使用尖括引用函数,并且我需要funcall在"关闭闭包"时调用.
它是因为#'并且funcall …
我想我明白发生了什么事。Lisp 仅将'match 子句'(1 2 3)和 的部分'(41 42 43)视为键(因为它们都扩展为(Quote... 并且从这个角度来看,第三个代码片段中的第二个'= (QUOTE... 是一个“重复键”(而实际上它不是)根本没有键。这只是我的语法错误)。
我认为我的主要问题是我没有正确理解编译器警告。
我不理解case(或 sbcl)的以下行为。
在这篇SO 帖子中,R. Joswig 指出,表单的 match 子句case不会被评估并被视为文字。因此匹配子句不应被引用。
我没有意识到这一点,引用了一个匹配条款,但忘记引用另一个。我不明白的是,为什么如果我引用一个匹配子句,编译器不会抱怨,但如果我引用两个匹配子句,编译器就会抱怨。具体来说:
> (let ((x 42))
(case x
((1 2 3) 'first-branch)
('(41 42 43) 'second-branch))) ; <= second match clause quoted
NIL
Run Code Online (Sandbox Code Playgroud)
=> 无警告。
> (let ((x 42))
(case x
('(1 2 3) 'first-branch) ; <= first match clause quoted
((41 …Run Code Online (Sandbox Code Playgroud) 函数位置的lambda表达式编译得很好:
> ((lambda (n) (> n 10)) 42)
T
Run Code Online (Sandbox Code Playgroud)
另一方面:
> (defun greater-than (x)
(lambda (n) (> n x)))
GREATER-THAN
> ((greater-than 10) 42)
Compile-time error: illegal function call
Run Code Online (Sandbox Code Playgroud)
不起作用.
(我显然需要打电话FUNCALL让它工作:(funcall (greater-than 10) 42)=> T.
我理解为什么带有函数对象作为值绑定的SYMBOL 必须不起作用,例如:(let ((foo (lambda () 42))) (foo)).单独的命名空间和所有这些.
但为什么禁止功能对象本身在功能位置?这个决定背后的理由是什么?
是一种setf能够在同一个地方在CLHS和位置在弱势族群的PAIP?
我试图找出Common Lisp中究竟是什么地方,但对我来说是HyperSpec的解释
地方 1.一种适合用作一般参考的表格.2.这样一个地方提到的概念位置[1].
只是有限的帮助.
(我知道这不是那种适合SO的问题,但如果有人知道一篇解释setfable/place/location的好文章,我会很感激链接/参考)
换句话说:CL中的变量是否可能不是(符号)的一部分?
我想我可能对CL中的变量有一种深刻的误解.
我一直认为CL没有变量,只有符号和符号(以及其他属性)具有名称和值单元格(这是变量).
当有人说"变量x具有值42"时,我认为它是"名称x存储值42 的值单元格"的缩写.
但这可能是错的.
当我输入
> (let ((a 42))
(type-of 'a))
SYMBOL
; caught STYLE-WARNING:
; The variable A is defined but never used.
Run Code Online (Sandbox Code Playgroud)
a在这个例子中,词汇变量是一个完全去肉的符号,其值单元格已设置为42?
因为警告The variable A is defined but never used暗示其他情况,并且看起来词汇变量a与下列形式的符号不同(type-of 'a).
在On Lisp(第84页)格雷厄姆说
‘(a b c)(没有逗号)等于’(a b c)
然后说
反引号列表相当于对引用元素的列表调用.
也就是说,‘(a b c)(没有逗号)等于(list ’a ’b ’c).
一个语句是因为假的'(a b c),并(list 'a 'b 'c)似乎并不相等.后者是一个新的consed列表(可以安全地修改),而前者是一个常量 - 或者至少规范允许编译器对其进行处理.
所以也许这是一个非常挑剔的问题,但是是一个反引号列表(没有逗号),如‘(a b c)等于'(a b c)或等于(list 'a 'b 'c)?