我终于开始学习函数式语言(emacs lisp),它明确区分了函数和特殊形式,例如流控制,例如if。
为什么特殊形式与功能不同,是否存在基本/理论上的原因?任何语言都提供功能if
?
由于
答案 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))
。
同样,您可以使用上述布尔值编码将or
,not
,while
,for
,...定义为函数。
答案 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作为计算的等价基础之间关系的核心。但是,在具有副作用的语言(如变量赋值)中使用它并没有多大用处,因为当事情发生时很重要。