为什么公共Lisp Lambda表达式是有效的函数名?

为什么公共Lisp Lambda表达式是有效的函数名?,lambda,common-lisp,function-call,Lambda,Common Lisp,Function Call,假设我想调用一些函数。如果我使用defun定义了函数,那么我只需在列表的开头使用函数名,后面跟着它的参数,如下所示(我将在示例中使用“=>”,以显示将代码输入到CLisp REPL中的输出): 快速的谷歌搜索显示LAMBDA既是一个符号也是一个宏。正在尝试展开宏对象: (macroexpand '(lambda (a) (+ a 12))) => #'(LAMBDA (A) (+ A 12)) 这是没有帮助的。我无法区分宏LAMBDA和符号LAMBDA,而且我完全不清楚为什么我可以使用L

假设我想调用一些函数。如果我使用defun定义了函数,那么我只需在列表的开头使用函数名,后面跟着它的参数,如下所示(我将在示例中使用“=>”,以显示将代码输入到CLisp REPL中的输出):

快速的谷歌搜索显示LAMBDA既是一个符号也是一个宏。正在尝试展开宏对象:

(macroexpand '(lambda (a) (+ a 12))) => #'(LAMBDA (A) (+ A 12))
这是没有帮助的。我无法区分宏LAMBDA和符号LAMBDA,而且我完全不清楚为什么我可以使用LAMBDA表达式作为函数名,而不是,比如说,#'f,据我所知,它应该以与#'(LAMBDA(a)(+a 12))相同的方式计算为函数f的有效函数指示符,但是:

(#'f 12) => *** - EVAL: #'F is not a function name; try using a symbol instead

LAMBDA是否是硬集规则的特殊例外,即计算表达式的第一个元素必须是某个操作的名称,或者是否存在一些我误解的更一致的规则集?

LAMBDA表达式和函数名称

lambda表达式不是函数名。公共Lisp中的函数名定义为符号或(setf符号)。lambda表达式基本上是用于描述匿名函数的内置语法

请注意,lambda表达式本身在公共Lisp中没有意义。它们仅以lambda形式(见下文)出现,并且在带有特殊运算符
函数的表单中出现

以表格形式列出

LAMBDA是否是硬集规则的特殊例外,即计算表达式的第一个元素必须是某个操作的名称,或者是否存在我误解的更一致的规则集

公共Lisp规范定义只有四种基于列表的表单。表单是一段有效的Lisp代码

  • 特殊表单(表单以特殊运算符开头)
  • 宏窗体(窗体以宏运算符开头)
  • 函数窗体(窗体以函数运算符开头)
  • lambda表单(表单以lambda表达式开头)
请参阅常见的Lisp HyperSpec:

请注意,CommonLisp中没有扩展此功能的机制。只有这四种类型的基于列表的表单。我们可以考虑扩展:数组作为函数,CLOS对象作为函数,不同类型的函数,如FEXPR、变量等等。。。对于基于列表的表单,公共Lisp语法不支持这些功能,并且没有可移植的机制来添加这些功能

LAMBDA

LAMBDA
在通用Lisp中有两个不同的用途:

  • 这是一个lambda表达式的头部
  • 作为宏
    LAMBDA
    。这将
    (lambda…)
    扩展为
    (函数(lambda…))

LAMBDA
被添加到第一语言定义CLtL1之后的公共Lisp中,以方便编写
(LAMBDA(x)x)
,而不是
(function(LAMBDA(x)x))
#'(LAMBDA(x)x)
。因此,它是函数特殊运算符形式的缩写,使代码看起来更简单,更像方案。

可以想象,在计算函数(即汽车没有命名宏或特殊运算符)表达式时,会发生以下转换:

(foo arg1 arg2 ...)
~~~>
(funcall (function foo) arg1 arg2 ...)
并将
function
理解为将表达式第一个元素中的内容转换为可以调用的实际函数运算符的特殊运算符。正是
函数
将lambda表达式(主要在编译时)转换为可以调用的闭包

最后请注意,
#'foo
(函数foo)
的缩写

在实践或规范中,这并不是实际工作的方式,因为
(function#'(setf foo))
是完全有效的,并且可以计算为一个存在的函数,但是
((setf foo)arg1 arg2…
不能是有效的函数调用


但是,这确实解释了为什么像
(#f x)
这样的表达式是无效的,原因是
(函数(函数f))
不是有效的表达式。

我认为问题在于lisp打印机,实现向我们展示了两个方面完全相同的东西,从内部看,它实际上是一个列表,而不是一个函数

常见且令人困惑的模式显示:

<i>[hao@wendy:~]$ ecl
;;; Loading "/nix/store/j48bf40ssnzgil3qmdc759y0navk079d-ecl-readline/lib/init.lsp"
n;;; Loading "/nix/store/j48bf40ssnzgil3qmdc759y0navk079d-ecl-readline/lib/ecl-readline.fas"
ix-;;; Loading "/nix/store/j48bf40ssnzgil3qmdc759y0navk079d-ecl-readline/lib/ecl-completions.fas"
sECL (Embeddable Common-Lisp) 16.1.3 (git:UNKNOWN)
Copyright (C) 1984 Taiichi Yuasa and Masami Hagiya
Copyright (C) 1993 Giuseppe Attardi
Copyright (C) 2000 Juan J. Garcia-Ripoll
Copyright (C) 2016 Daniel Kochmanski
ECL is free software, and you are welcome to redistribute it
under certain conditions; see file 'Copyright' for details.
Type :h for Help.  
Top level in: #<process TOP-LEVEL>.
h+CL-USER[1]> (macroexpand '(lambda (a) (+a 12)))
#'(LAMBDA (A) (+A 12))
T
+CL-USER[2]> (equal (macroexpand '(lambda (a) (+ a 12))) '(lambda (a) (+ a 12)))
NIL
+CL-USER[3]> (map 'list #'type-of (list (macroexpand '(lambda (a) (+ a 12))) '(lambda (a) (+ a 12))))
(CONS CONS)
+CL-USER[4]> (map 'list #'functionp (list (macroexpand '(lambda (a) (+ a 12))) '(lambda (a) (+ a 12))))
(NIL NIL)
+CL-USER[5]> (map 'list #'car (list (macroexpand '(lambda (a) (+ a 12))) '(lambda (a) (+ a 12))))
#'LAMBDA
我试图强迫打印机显式显示定义[22]的
(函数(lambda…)
部分,但我记不起上次我做了完全相同的事情,试图找出为什么在开始信任lisp时微妙地出现了这个问题

+CL-USER[21]> (type-of (car the-funs)))
CONS
;;; Warning: Ignoring an unmatched right parenthesis.
+CL-USER[22]> (car (car the-funs))
FUNCTION
实际上,我们所做的是一个列表/缺点(见下)和一个函数(见上)

也许区别不仅仅是视觉上的印刷字符;以下是SBCL:

<i>[hao@wendy:~]$ sbcl
This is SBCL 2.0.0.nixos, an implementation of ANSI Common Lisp.
More information about SBCL is available at <http://www.sbcl.org/>.

SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses.  See the CREDITS and COPYING files in the
distribution for more information.
* (setq fs (list (macroexpand '(lambda (x) (1+ x))) '(lambda (x) (1+ x))))
; in: SETQ FS
;     (SETQ FS (LIST (MACROEXPAND '(LAMBDA # #)) '(LAMBDA (X) (1+ X))))
; 
; caught WARNING:
;   undefined variable: COMMON-LISP-USER::FS
; 
; compilation unit finished
;   Undefined variable:
;     FS
;   caught 1 WARNING condition
(#'(LAMBDA (X) (1+ X)) (LAMBDA (X) (1+ X)))

* (let (*print-pretty*) (print (lambda (x) (1+ x))))

#<FUNCTION (LAMBDA (X)) {52B1CABB}> 
#<FUNCTION (LAMBDA (X)) {52B1CABB}>
* (let (*print-pretty*) (print ' (lambda (x) (1+ x))))

(LAMBDA (X) (1+ X)) 
(LAMBDA (X) (1+ X))
最后,(不要)在森林中进行随机树漫游,确认我们可以漫游列表,但函数只是关闭

* (defun walk-tree (fun tree)
  (subst-if t
            (constantly nil)
            tree
            :key fun))
WALK-TREE
* (walk-tree 'print (lambda (x) (1+ x)))

#<FUNCTION (LAMBDA (X)) {52B1CD5B}> 
#<FUNCTION (LAMBDA (X)) {52B1CD5B}>
* (walk-tree 'print '(lambda (x) (1+ x))))

(LAMBDA (X) (1+ X)) 
LAMBDA 
((X) (1+ X)) 
(X) 
X 
NIL 
((1+ X)) 
(1+ X) 
1+ 
(X) 
X 
NIL 
NIL 
(LAMBDA (X) (1+ X))
* (defun walk-tree-atoms (fun tree)
  (tree-equal tree tree
              :test (lambda (element-1 element-2)
                      (declare (ignore element-2))
                      (funcall fun element-1)
                      t)))
WALK-TREE-ATOMS
* (walk-tree-atoms 'print (lambda (x) (1+ x)))

#<FUNCTION (LAMBDA (X)) {52B1CF9B}> 
T
* (walk-tree-atoms 'print '(lambda (x) (1+ x)))

LAMBDA 
X 
NIL 
1+ 
X 
NIL 
NIL 
T
* (quit)

<i>[hao@wendy:~]$ 
*(defun步行树(趣味树)
(如果t
(始终为零)
树
:主要乐趣)
步行树
*(行走树打印(λ(x)(1+x)))
# 
#
*(行走树“打印”(λ(x)(1+x)))
(λ(X)(1+X))
兰姆达
((X)(1+X))
(十)
X
无
((1+X))
(1+X)
1+ 
(十)
X
无
无
(λ(X)(1+X))
*(defun步行树原子(趣味树)
(树等于树
:测试(λ(元件-1元件-2)
(声明(忽略元素2))
(funcall-fun元素-1)
t) ))
步行树原子
*(行走树原子印花(λ(x)(1+x)))
# 
T
*(行走树原子“打印”(λ(x)(1+x)))
兰姆达
X
无
1+ 
X
无
无
T
*(退出)
[hao@wendy:~]$ 
行走功能取自LispTips,很遗憾,它似乎被删除了,当我读到这篇文章时,我有一个倒叙,你仍然可以
+CL-USER[21]> (type-of (car the-funs)))
CONS
;;; Warning: Ignoring an unmatched right parenthesis.
+CL-USER[22]> (car (car the-funs))
FUNCTION
+CL-USER[23]> (values #1=(cadr the-funs) (type-of #1#))
(LAMBDA (A) (+ A 12))
CONS
<i>[hao@wendy:~]$ sbcl
This is SBCL 2.0.0.nixos, an implementation of ANSI Common Lisp.
More information about SBCL is available at <http://www.sbcl.org/>.

SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses.  See the CREDITS and COPYING files in the
distribution for more information.
* (setq fs (list (macroexpand '(lambda (x) (1+ x))) '(lambda (x) (1+ x))))
; in: SETQ FS
;     (SETQ FS (LIST (MACROEXPAND '(LAMBDA # #)) '(LAMBDA (X) (1+ X))))
; 
; caught WARNING:
;   undefined variable: COMMON-LISP-USER::FS
; 
; compilation unit finished
;   Undefined variable:
;     FS
;   caught 1 WARNING condition
(#'(LAMBDA (X) (1+ X)) (LAMBDA (X) (1+ X)))

* (let (*print-pretty*) (print (lambda (x) (1+ x))))

#<FUNCTION (LAMBDA (X)) {52B1CABB}> 
#<FUNCTION (LAMBDA (X)) {52B1CABB}>
* (let (*print-pretty*) (print ' (lambda (x) (1+ x))))

(LAMBDA (X) (1+ X)) 
(LAMBDA (X) (1+ X))
#<FUNCTION (LAMBDA (X)) {52B1CABB}> 
(LAMBDA (X) (1+ X))
* (mapcar #'functionp fs) 
(NIL NIL)
* (mapcar #'type-of fs)
(CONS CONS)
* (mapcar #'car fs)
#'LAMBDA
* (values (car (car fs)) (car (cdr fs)))
FUNCTION
(LAMBDA (X) (1+ X))
* (defun walk-tree (fun tree)
  (subst-if t
            (constantly nil)
            tree
            :key fun))
WALK-TREE
* (walk-tree 'print (lambda (x) (1+ x)))

#<FUNCTION (LAMBDA (X)) {52B1CD5B}> 
#<FUNCTION (LAMBDA (X)) {52B1CD5B}>
* (walk-tree 'print '(lambda (x) (1+ x))))

(LAMBDA (X) (1+ X)) 
LAMBDA 
((X) (1+ X)) 
(X) 
X 
NIL 
((1+ X)) 
(1+ X) 
1+ 
(X) 
X 
NIL 
NIL 
(LAMBDA (X) (1+ X))
* (defun walk-tree-atoms (fun tree)
  (tree-equal tree tree
              :test (lambda (element-1 element-2)
                      (declare (ignore element-2))
                      (funcall fun element-1)
                      t)))
WALK-TREE-ATOMS
* (walk-tree-atoms 'print (lambda (x) (1+ x)))

#<FUNCTION (LAMBDA (X)) {52B1CF9B}> 
T
* (walk-tree-atoms 'print '(lambda (x) (1+ x)))

LAMBDA 
X 
NIL 
1+ 
X 
NIL 
NIL 
T
* (quit)

<i>[hao@wendy:~]$