我试图更好地理解S-表达式是如何用不同的语言进行计算的,并希望看到它们能够处理有趣的、格式错误的表达式。我知道Common和Scheme是完全不同的语言,但是它们在语义上是否有特定的差异来解释行为上的差异。例如,Lisp-1和Lisp-2在行为上有明显的差异,卫生和非卫生的宏系统也是如此。
我有一个程序,其中包含一个无法到达的格式错误的if表达式,在Scheme和Common中。
;; foo.scm
(if #t 1 (if))
(display "12")和通用Lisp版本
;; foo.lisp
(if t 1 (if))
(display "12")chicken和guile都会产生语法错误。
鸡:
% 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) <--诡计:
% guile foo.scm
...
.../foo.scm:1:9: source expression failed to match any pattern in form (if)sbcl和clisp都打印12并且不发出警告。
SBCL:
% sbcl --load foo.lisp
This is SBCL 1.3.11, an implementation of ANSI Common Lisp.
...
12
0]^DCLISP
% clisp foo.lisp
"12"发布于 2016-11-04 05:48:12
通用Lisp的实现:解释器和编译器
在通用Lisp中,代码执行的类型取决于Lisp系统实现了什么以及您如何使用它。通用Lisp实现通常有多种方式来执行代码:解释器和一个或多个编译器。即使一个正在运行的实现也可能具有这种功能,并且它将允许用户在这些实现之间进行切换。
GNU有一个解释器和一个编译器。
在GNU CLISP中的示例:
文本文件的加载通常使用解释器:
[1]> (load "test.lisp")
;; Loading file test.lisp ...
;; Loaded file test.lisp
T解释器不会检测错误,因为它没有检查整个表达式的语法正确性。因为从来不使用带有语法错误的else子句,所以解释器将永远不会查看它。
CLISP还有一个编译器:
[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表单,则计算程序不会使用完全编译,也不会捕获错误:
CL-USER> (if t 1 (if))
1如果在函数定义中编写相同的代码,则会检测到错误,因为默认情况下将编译函数定义:
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解释器,则在定义时不会检测到该错误:
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实现中,您需要使用编译器来获得完整的语法警告/错误。
发布于 2016-11-04 15:21:49
看来CL部件是由Rainer很好地处理的。我只想指出,R5RS不需要像您的两个实现那样行事。
R5RS是非常未指定的,对于if,它只指定在正确使用时应该做什么,我们有这篇关于错误处理的文章
当谈到错误情况时,此报告使用“错误信号”这一短语来表示实现必须检测和报告错误。如果在讨论错误时没有出现这样的措辞,那么实现就不需要检测或报告错误,尽管鼓励它们这样做。实现不需要检测的错误情况通常被简单地称为“错误”。
因此,要在R5RS中总结这一点,字符串"banana"就像对(if #t 1 (if))的评估的Guile和this响应一样正确。
另一方面,R6RS一般表示当实现检测到异常情况时,会引发异常。。这意味着少于两个表达式或多于3个表达式的if应该会引发异常,但它并没有说它必须发生编译时,因为语言可能正在解析和解释。
https://stackoverflow.com/questions/40415335
复制相似问题