首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >无法到达的Ill格式if-表达式在Scheme中是语法错误,但在公共Lisp中不是。

无法到达的Ill格式if-表达式在Scheme中是语法错误,但在公共Lisp中不是。
EN

Stack Overflow用户
提问于 2016-11-04 04:33:46
回答 2查看 728关注 0票数 4

我试图更好地理解S-表达式是如何用不同的语言进行计算的,并希望看到它们能够处理有趣的、格式错误的表达式。我知道Common和Scheme是完全不同的语言,但是它们在语义上是否有特定的差异来解释行为上的差异。例如,Lisp-1和Lisp-2在行为上有明显的差异,卫生和非卫生的宏系统也是如此。

我有一个程序,其中包含一个无法到达的格式错误的if表达式,在Scheme和Common中。

代码语言:javascript
复制
;; foo.scm
(if #t 1 (if))

(display "12")

和通用Lisp版本

代码语言:javascript
复制
;; foo.lisp
(if t 1 (if))

(display "12")

chickenguile都会产生语法错误。

鸡:

代码语言:javascript
复制
% chicken foo.scm

Syntax error: (foo.scm:1) in `if' - pair expected

    (if)

    Expansion history:

    <syntax>      (##core#begin (if #t 1 (if)))
    <syntax>      (if #t 1 (if))
    <syntax>      (##core#if #t 1 (if))
    <syntax>      (if)  <--

诡计:

代码语言:javascript
复制
% guile foo.scm
...
.../foo.scm:1:9: source expression failed to match any pattern in form (if)

sbclclisp都打印12并且不发出警告。

SBCL:

代码语言:javascript
复制
% sbcl --load foo.lisp
This is SBCL 1.3.11, an implementation of ANSI Common Lisp.
...
12
0]^D

CLISP

代码语言:javascript
复制
% clisp foo.lisp

"12"
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-11-04 05:48:12

通用Lisp的实现:解释器和编译器

在通用Lisp中,代码执行的类型取决于Lisp系统实现了什么以及您如何使用它。通用Lisp实现通常有多种方式来执行代码:解释器和一个或多个编译器。即使一个正在运行的实现也可能具有这种功能,并且它将允许用户在这些实现之间进行切换。

  • 解释器:直接从Lisp数据结构执行。它不是虚拟机代码的解释器,就像JVM一样。人们不会期望解释器在执行过程中验证完整的代码树/图。解释器通常只查看它执行的当前顶部表单。
  • 编译器:将Lisp代码编译为C、某些字节码或机器代码。因为编译器在代码运行之前生成代码,所以它将对所有代码进行语法检查(关于可能出现的异常,请参见它看到的注释)。
  • Toplevel评估:可以使用解释器、编译器或两者混合使用。

GNU有一个解释器和一个编译器

在GNU CLISP中的示例:

文本文件的加载通常使用解释器:

代码语言:javascript
复制
[1]> (load "test.lisp")
;; Loading file test.lisp ...
;; Loaded file test.lisp
T

解释器不会检测错误,因为它没有检查整个表达式的语法正确性。因为从来不使用带有语法错误的else子句,所以解释器将永远不会查看它。

CLISP还有一个编译器:

代码语言:javascript
复制
[2]> (compile-file "test.lisp")
;; Compiling file /tmp/test.lisp ...
** - Continuable Error
in #:|1 1 (IF T 1 ...)-1| in line 1 : Form too short, too few arguments: (IF)
If you continue (by typing 'continue'): Ignore the error and proceed
The following restarts are also available:
ABORT          :R1      Abort main loop

正如您所看到的,CLISP编译器检测语法错误并提供明确的错误消息。

SBCL使用编译器,但也有解释器

在默认情况下,SBCL使用编译器来检测错误。对于顶级表单,它使用了一种更简单的评估机制。还可以切换到解释器。

如果您在SBCL中编写了一个简单的If表单,则计算程序不会使用完全编译,也不会捕获错误:

代码语言:javascript
复制
CL-USER> (if t 1 (if))
1

如果在函数定义中编写相同的代码,则会检测到错误,因为默认情况下将编译函数定义:

代码语言:javascript
复制
CL-USER> (defun foo () (if t 1 (if)))
; in: DEFUN FOO
;     (IF)
; 
; caught ERROR:
;   error while parsing arguments to special operator IF:
;     too few elements in
;       ()
;     to satisfy lambda list
;       (SB-C::TEST SB-C::THEN &OPTIONAL SB-C::ELSE):
;     between 2 and 3 expected, but got 0
; 
; compilation unit finished
;   caught 1 ERROR condition
WARNING: redefining COMMON-LISP-USER::FOO in DEFUN
FOO

如果要切换到完整的SBCL解释器,则在定义时不会检测到该错误:

代码语言:javascript
复制
CL-USER> (setf *evaluator-mode* :interpret)
:INTERPRET
CL-USER> (defun foo () (if t 1 (if)))
WARNING: redefining COMMON-LISP-USER::FOO in DEFUN
FOO

优化和语法检查

请注意,一些优化编译器可能不会检查不可访问代码的语法。

摘要

在大多数Common实现中,您需要使用编译器来获得完整的语法警告/错误。

票数 8
EN

Stack Overflow用户

发布于 2016-11-04 15:21:49

看来CL部件是由Rainer很好地处理的。我只想指出,R5RS不需要像您的两个实现那样行事。

R5RS是非常未指定的,对于if,它只指定在正确使用时应该做什么,我们有这篇关于错误处理的文章

当谈到错误情况时,此报告使用“错误信号”这一短语来表示实现必须检测和报告错误。如果在讨论错误时没有出现这样的措辞,那么实现就不需要检测或报告错误,尽管鼓励它们这样做。实现不需要检测的错误情况通常被简单地称为“错误”。

因此,要在R5RS中总结这一点,字符串"banana"就像对(if #t 1 (if))的评估的Guile和this响应一样正确。

另一方面,R6RS一般表示当实现检测到异常情况时,会引发异常。。这意味着少于两个表达式或多于3个表达式的if应该会引发异常,但它并没有说它必须发生编译时,因为语言可能正在解析和解释。

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

https://stackoverflow.com/questions/40415335

复制
相关文章

相似问题

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