如果是一个适当的功能,而不是一个特殊的形式

时间:2010-02-10 22:15:37

标签: function lisp functional-programming special-form

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

为什么特殊形式与功能不同,是否存在基本/理论上的原因?任何语言都提供功能if

由于

7 个答案:

答案 0 :(得分:12)

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

急切评估:在调用函数之前,评估函数的参数,并且只将结果传递给函数。

延迟评估:当且仅当访问它们时才评估函数的参数。

答案 1 :(得分:8)

如果if是正常函数,则其参数 - 然后形成 else形式 - 将 调用if函数之前评估,因为这是function evaluation的规则:计算所有参数以生成值,然后提供该值序列作为列表中第一个符号指定的函数的参数。

相反,使用if您想要做的只是评估其中一个然后表单 else表单,而不是两者。为了抑制对其中一个的评估,您需要一个宏或special form

答案 2 :(得分:3)

在Emacs Lisp和Common Lisp等语言中,特殊形式是内置语言结构。它们具有正常函数调用的不同评估规则。对于正常函数调用,将评估所有参数。因此,您不能将IF写为普通函数 - 该条件确定要评估哪个子句。通常你也不能编写自己的特殊表单 - 在Common Lisp中没有用于定义特殊表单的语言结构(尽管单个实现必须以某种方式实现现有的。这会导致宏。使用宏,你可以编写一个语法转换将一个表达式转换为另一个表达式。为了能够将IF作为宏编写,你需要有另一个条件形式,你可以将它用于转换后的代码.Lisp提供条件作为基本结构。让我们假设COND是一个基本结构,那么你可以将IF扩展为使用COND。

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))

答案 3 :(得分:1)

简短回答:不。

长(呃)答案:(如果......)要求你控制参数的评估顺序。 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]> 

答案 4 :(得分: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))

然后功能变为:

(define (function_if c (t) (e))
  (c (t) (e)))

(function_if true 'true 'false)
==> true

另一个例子是,函数and的定义是(define (and p (q)) (p (q) false))

同样,您可以使用上述布尔值编码将ornotwhilefor,...定义为函数。

答案 5 :(得分:0)

在Scala中,可以使用call-by-name参数对if进行正确的副作用评估。

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

这些功能也可用于模拟大量new control structures

答案 6 :(得分:0)

IF可以是具有按名称语义(懒惰评估)的函数式语言中的函数,如Lambda Calculus或Algol。事实上,我认为,Turing Machines and Lambda Calculus作为计算的等价基础之间关系的核心。但是,在具有副作用的语言(如变量赋值)中使用它并没有多大用处,因为事情发生时很重要。