首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >“its”如何评估其所有论点?

“its”如何评估其所有论点?
EN

Stack Overflow用户
提问于 2013-09-29 10:48:17
回答 6查看 1.3K关注 0票数 11

我正在努力学习和理解Lisp编程语言。函数+按应用顺序计算其参数:

代码语言:javascript
复制
(+ 1 (+ 1 2))

将对(+ 1 2)进行评估,然后对(+ 1 3)进行评估,但if函数的工作方式不同:

代码语言:javascript
复制
(if (> 1 2) (not-defined 1 2) 1)

由于没有计算表单(not-defined 1 2),所以程序不会中断。

相同的语法如何导致不同的参数计算?如何定义if函数,使其参数不被计算?

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2013-09-29 11:49:48

if是一个特殊算子,不是一个普通的函数。

这意味着在调用与rest元素关联的函数之前计算复合形式中的first元素的正常规则是,而不是(因为它类似于宏观形式)。

在编译器和/或解释器中实现这一点的方法是查看复合表单并根据元素决定如何处理它:

  • 如果它是一个特殊的操作员,它就做它的特殊的事情;
  • 如果它是一个,它的宏函数得到整个表单;
  • 否则,它将被视为一个函数--即使没有定义函数。

请注意,一些特殊的表单可以定义为扩展到其他特殊形式的宏,但实际上必须存在一些特殊的表单。

例如,我们可以用if来定义cond

代码语言:javascript
复制
(defmacro my-if (condition yes no) 
  `(cond (,condition ,yes)
         (t ,no)))

反之亦然(实际上,cond是一个宏,通常扩展为一个if序列)。

PS。请注意,系统提供的宏和特殊操作符之间的区别,虽然在技术上清晰明了(参见special-operator-pmacro-function),但在意识形态上却模糊了因为

实现可以自由地将Common特殊运算符作为宏实现。实现可以自由地将任何宏运算符实现为特殊运算符,但前提是还提供了宏的等效定义。

票数 14
EN

Stack Overflow用户

发布于 2013-09-29 11:56:06

Lisp语法是规则的,比其他语言规则得多,但它仍然不是完全规则的:例如

代码语言:javascript
复制
(let ((x 0))
   x)

let不是函数的名称,((x 0))也不是一个糟糕的表单,其中第一个位置使用了一个不是lambda表单的列表。

当然,有很多“特殊情况”(当然比其他语言少得多),每个列表的一般规则都是函数调用,而if就是其中之一。常见的Lisp有相当多的“特殊形式”(因为绝对极简性不是重点),但您可以使用一个方案方言,其中只有五个:ifprognquotelambdaset! (如果您想要宏的话,可以使用六个)。

虽然Lisp的语法并不完全统一,但是代码的底层representation是相当统一的(仅仅是列表和原子),表示的一致性和简单性是元编程(宏)的便利因素。

"Lisp没有语法“是一种有一定真实性的语句,但它是"Lisp有两个语法”的语句:一种语法是使用reader将字符流转换为s-表达式,另一种语法是使用编译器/计算器将s-表达式转换为可执行代码。

另外,Lisp没有语法,因为这两个级别都不是固定的。与其他编程语言不同,您可以定制第一步(使用读取器宏)和第二步(使用宏)。

票数 5
EN

Stack Overflow用户

发布于 2013-09-29 18:38:10

sds的回答很好地回答了这个问题,但我认为还有几个更一般的方面值得提及。正如这个答案和其他人所指出的,if作为一种特殊的运算符被内置于语言中,因为它实际上是一种原语。最重要的是,if不是一个函数。

也就是说,if的功能可以通过只使用函数和调用所有参数的普通函数来实现。因此,条件词可以在lambda微积分中实现,家族中的语言在某种程度上是基于这些语言的,但是没有条件运算符。

在lambda演算中,可以将true和false定义为两个参数的函数。这些参数被假定为函数,真调用第一个参数,假调用第二个参数。(这是教堂布尔人的一个细微变化,它只是返回第一个或第二个参数。)

代码语言:javascript
复制
 true = λ[x y].(x)
false = λ[x y].(y)

(这显然与Common中的布尔值不同,其中nil为false,而任何其他值都为真。)但是,这样做的好处是,我们可以使用一个布尔值来调用两个函数中的一个,这取决于布尔值是真还是假。考虑一下通用Lisp表单:

代码语言:javascript
复制
(if some-condition
  then-part
  else-part)

如果正使用上述定义的布尔值,则计算some-condition将生成truefalse,如果我们使用参数调用该结果

代码语言:javascript
复制
(lambda () then-part)
(lambda () else-part)

然后只调用其中一个,因此实际上只会对then-partelse-part中的一个进行计算。通常,将某些表单封装在lambda中是延迟对这些表单进行评估的好方法。

Common宏系统的强大功能意味着我们实际上可以使用上面描述的布尔类型定义一个if宏:

代码语言:javascript
复制
(defconstant true
  (lambda (x y)
    (declare (ignore y))
    (funcall x)))

(defconstant false
  (lambda (x y)
    (declare (ignore x))
    (funcall y)))

(defmacro new-if (test then &optional else)
  `(funcall ,test
            (lambda () ,then)
            (lambda () ,else)))

有了这些定义,一些代码如下:

代码语言:javascript
复制
(new-if (member 'a '(1 2 3))
  (print "it's a member")
  (print "it's not a member"))))

扩大到这一点:

代码语言:javascript
复制
(FUNCALL (MEMBER 'A '(1 2 3))                     ; assuming MEMBER were rewritten 
         (LAMBDA () (PRINT "it's a member"))      ; to return `true` or `false`
         (LAMBDA () (PRINT "it's not a member")))

通常,如果有某种形式而有些参数没有得到计算,那么(car )表单要么是一个Common特殊运算符,要么是一个宏。如果您需要编写一个函数,其中将对参数进行计算,但不想对某些表单进行计算,则可以将它们封装在lambda表达式中,并让函数有条件地调用这些匿名函数。

如果您还没有在语言中使用if,这是实现该语言的一种可能的方法。当然,现代计算机硬件不是基于lambda演算解释器,而是基于具有测试和跳转指令的CPU,因此语言提供一个原语并编译到适当的机器指令是更有效的。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19077142

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档