什么时候列表是列表,什么时候列表是应用程序?

When is a list a list, and when is a list an application?

我正在尝试学习一些类型理论。这是使用作者写的称为 pie 的 lisp 方言来教授的。

假设我们已经定义了一些函数 f,它接受一个 A 类型的参数并产生 B 类型的输出,我有一些 a 是类型 A.

如果我尝试输入表达式:

(f a)

我无法在两种可能的结果之间做出决定:

  1. 这是一个列表,其第一个元素是某个 A->B,其第二个元素是某个 A
  2. 它是 B 类的东西...因为它是一个应用程序

list什么时候是list,什么时候是application?如果我想要函数列表怎么办,这将如何工作,如何阻止列表被解释为应用程序?

当您键入它时,它只是文本(5 个字符)。当你以 Lisp 语法阅读它时,它变成了一个列表(或 form)。当你评估它时,它被评估为一个函数应用程序,它有一个值作为结果。

为了或者定义一个函数,通常的符号是lambda(或者λ ),它表示一个特殊的运算符,它从表单的其余部分创建一个函数。例如,要创建一个将 f 应用于某个值两次的函数,您可以编写 (lambda (x) (f (f x))).

(确切的语义可能会因 Lisp 方言而有所不同。)

为了创建某物的列表,您使用函数 list。例如,以下计算结果为两个函数的列表:

(list (lambda (x) (f (f x)))
      (lambda (x) (f x)))

列表与函数应用程序之间没有本质区别。它完全取决于您如何使用它。如果您打算对其进行评估,那么它就是一个应用程序(或其他类型的程序代码);否则,它只是数据。

这是 Lisp 的强大功能之一:它还允许您将程序代码视为普通数据。这在 Lisp 宏中最为明显:它们采用程序代码,将其作为列表结构进行操作,并且 return 打算在其位置进行评估的新列表结构。

注意,顺便说一句,在许多 Lisp 方言(例如 Common Lisp)中,应用程序的第一个元素不是函数,它是函数名称或 lambda 表达式。例如。你可以这样做:

(eval (list 'print 3)) # car is the symbol PRINT

但不是

(eval (list #'print 3)) # car is the PRINT function.

表达式(f a)是以f作为第一个标识符,a作为第二个标识符的形式。这永远不可能是列表,除非 f 是语法*(宏)。

因此 f 被评估为某个对象,该对象以评估的 a 作为参数应用。如果 f 的计算结果不是函数对象,您将收到错误消息,因为它无法应用。

您可以使用 quote 创建文字列表。例如。 (quote (f a)) 或语法缩写 '(f a) 应用语法 quote 将其参数评估为数据。例如。包含两个符号的列表,fa.

您可以使用 cons 动态创建列表。例如。 (cons 'f (cons 'a '())) 创建一个新列表 (f a) 并且 (list 'f 'a) 是一个函数,它以参数作为元素创建一个 cons 链。

如果您想创建一个包含两个函数的列表,您可以执行 (cons + (cons - '()))(list + -) 并且它们没有被应用,因为它们没有括号。如果您要执行 (list (+) (-)),它们都会以零参数应用,并且列表结果为 (0 0)。请注意,+- 只是此处被评估为函数对象的变量。您可以使用 lambda 创建新的函数对象,例如。 (lambda (arg) (* arg arg)) 是 square 的一个实现。它们需要被评估才能成为函数,所以你不能把它们放在文字中。例如。 '((lambda (arg) (* arg arg)) +) 将成为一个列表,第一个元素是带有符号 lambda 的列表,第二个元素是符号 +。 None 与功能有关。