什么时候列表是列表,什么时候列表是应用程序?
When is a list a list, and when is a list an application?
我正在尝试学习一些类型理论。这是使用作者写的称为 pie 的 lisp 方言来教授的。
假设我们已经定义了一些函数 f,它接受一个 A 类型的参数并产生 B 类型的输出,我有一些 a 是类型 A.
如果我尝试输入表达式:
(f a)
我无法在两种可能的结果之间做出决定:
- 这是一个列表,其第一个元素是某个 A->B,其第二个元素是某个 A
- 它是 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
将其参数评估为数据。例如。包含两个符号的列表,f
和 a
.
您可以使用 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 与功能有关。
我正在尝试学习一些类型理论。这是使用作者写的称为 pie 的 lisp 方言来教授的。
假设我们已经定义了一些函数 f,它接受一个 A 类型的参数并产生 B 类型的输出,我有一些 a 是类型 A.
如果我尝试输入表达式:
(f a)
我无法在两种可能的结果之间做出决定:
- 这是一个列表,其第一个元素是某个 A->B,其第二个元素是某个 A
- 它是 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
将其参数评估为数据。例如。包含两个符号的列表,f
和 a
.
您可以使用 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 与功能有关。