15

我终于开始学习函数式语言(emacs lisp),它明确区分了函数和特殊形式,例如流控制,例如 if。

特殊形式与功能不同是否有基本/理论原因?有任何语言提供功能if吗?

谢谢

4

7 回答 7

13

急切评估需要区分,具有惰性评估的语言(即 Haskell)if 等。可以是函数。

急切求值:函数的参数在调用函数之前求值,只有结果传递给函数。

惰性求值:当且仅当它们被访问时才对函数的参数求值。

于 2010-02-10T22:24:42.873 回答
8

如果if是一个普通函数,那么它的两个参数(then形式else 形式)将在调用函数之前进行评估if,因为这是函数评估的规则:评估所有参数以产生值,然后将值序列提供为列表中第一个符号指定的函数的参数。

相反,if您想要做的是准确评估then 形式else 形式之一,而不是两者。为了抑制对其中一个或另一个的评估,您需要一个宏或一个特殊的形式

于 2010-02-10T22:31:49.583 回答
3

在 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))
于 2010-02-11T12:56:08.480 回答
1

简短的回答:没有。

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]> 
于 2010-02-11T09:36:18.660 回答
1

为了完整性:例如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

于 2010-02-11T12:20:29.360 回答
0

在 Scala 中,可以if使用按名称调用的参数对正确的副作用评估进行建模。

def If[A](cond : Boolean, truePart : => A, falsePart : => A) = if (cond) truePart else falsePart

这些特性也可用于模拟许多新的控制结构

于 2010-02-11T16:00:53.583 回答
0

IF 可以是具有按名称调用语义(惰性求值)的函数式语言中的函数,如 Lambda Calculus 或 Algol。事实上,我认为,这是图灵机和 Lambda 微积分之间关系的核心,它们是计算的等效基础。但是,在具有副作用的语言中(例如对变量的赋值),它并没有多大用处,因为事情发生时很重要。

于 2010-03-15T18:20:17.907 回答