我终于开始学习函数式语言(emacs lisp),它明确区分了函数和特殊形式,例如流控制,例如 if。
特殊形式与功能不同是否有基本/理论原因?有任何语言提供功能if
吗?
谢谢
我终于开始学习函数式语言(emacs lisp),它明确区分了函数和特殊形式,例如流控制,例如 if。
特殊形式与功能不同是否有基本/理论原因?有任何语言提供功能if
吗?
谢谢
急切评估需要区分,具有惰性评估的语言(即 Haskell)if 等。可以是函数。
急切求值:函数的参数在调用函数之前求值,只有结果传递给函数。
惰性求值:当且仅当它们被访问时才对函数的参数求值。
在 Emacs Lisp 和 Common Lisp 等语言中,特殊形式是内置的语言结构。它们具有正常函数调用的不同评估规则。对于正常的函数调用,所有参数都被评估。因此,您不能将 IF 编写为普通函数 - 条件确定评估哪个子句。通常你也不能编写自己的特殊形式——在 Common Lisp 中没有用于定义特殊形式的语言结构(尽管个别实现必须以某种方式实现现有的。这导致宏。使用宏,你可以编写句法转换将一个表达式转换为另一个表达式。为了能够将 IF 编写为宏,您需要有另一种条件形式,您可以将其用于转换后的代码。Lisp 提供条件作为基本结构。让'
MY-IF 作为 Common Lisp 中的宏:
(defmacro my-if (condition true-clause false-clause)
`(cond (,condition ,true-clause)
(t ,false-clause)))
所以
(my-if (foo-p) 'one 'two)
扩展到
(cond ((foo-p) 'one)
(t 'two))
简短的回答:没有。
Long(er) answer: (if ...) 要求您控制参数的评估顺序。Lisp 作为一种热切的语言不能在函数中做到这一点。
解决方法:在宏中执行:
(defmacro _if (cnd true false)
(let ( (gcond (gensym))
(gresp (gensym)))
`(let ( (,gcond ,cnd) ;`#quotes
(,gresp nil))
(and ,gcond (setf ,gresp (multiple-value-list ,true)))
(and (not ,gcond) (setf ,gresp (multiple-value-list ,false)))
(values-list ,gresp))))
例如:
[dsm@localhost:~]$ clisp -q
[1]> (defmacro _if (cnd true false)
(let ( (gcond (gensym))
(gresp (gensym)))
`(let ( (,gcond ,cnd) ;`#quotes
(,gresp nil))
(and ,gcond (setf ,gresp (multiple-value-list ,true)))
(and (not ,gcond) (setf ,gresp (multiple-value-list ,false)))
(values-list ,gresp))))
_IF
[2]> (_if (= 1 1) (+ 2 3) "bar")
5
[3]> (_if (= 1 2) (+ 2 3) "bar")
"bar"
[4]>
为了完整性:例如Pico语言中没有特殊形式,并且if
是一个原始函数,而 Pico 受 Scheme 的启发,默认情况下具有急切求值。
在Scheme中你可以写
(define (true t f)
(t))
(define (false t f)
(f))
(define (function_if c t e)
(c t e))
进而
(function_if true (lambda () 'true) (lambda () 'false))
==> true
使 Pico 易于管理的原因在于,您可以定义函数参数,这些函数参数采用“自动”延迟的函数参数。这意味着您不必自己在 lambdas 中进行包装。因此,Pico 具有急切的评估,但具有按需延迟评估,绕过了对特殊表格的需求。
因此,在带有函数参数的 Scheme 语法中,您可以将布尔值编码为:
(define (true (t) (f))
(t))
(define (false (t) (f))
(f))
然后函数 if 变为:
(define (function_if c (t) (e))
(c (t) (e)))
和
(function_if true 'true 'false)
==> true
再举一个例子,函数的定义and
是(define (and p (q)) (p (q) false))
。
同样,您可以使用上述布尔编码将or
, not
, while
, , ... 定义为函数。for
在 Scala 中,可以if
使用按名称调用的参数对正确的副作用评估进行建模。
def If[A](cond : Boolean, truePart : => A, falsePart : => A) = if (cond) truePart else falsePart
这些特性也可用于模拟许多新的控制结构。
IF 可以是具有按名称调用语义(惰性求值)的函数式语言中的函数,如 Lambda Calculus 或 Algol。事实上,我认为,这是图灵机和 Lambda 微积分之间关系的核心,它们是计算的等效基础。但是,在具有副作用的语言中(例如对变量的赋值),它并没有多大用处,因为当事情发生时很重要。