2016-11-04 33 views
4

我试图更好地理解S表达式在不同Lisp中的评估方式,并希望看到它们能够处理有趣的不合格表达式。我知道Common Lisp和Scheme是完全不同的语言,但是它们的语义在解释行为上的差异方面存在特定的差异。例如,Lisp-1和Lisp-2在行为方面有明显的差异,卫生型和非卫生型宏观系统也有差异。无法到达Ill-expression if-expression在Scheme中是语法错误,但不是Common Lisp

我有一个程序,其中包含在Scheme和Common Lisp中表达式表达式无法到达的不合格

;; foo.scm 
(if #t 1 (if)) 

(display "12") 

而Common Lisp的版本

;; foo.lisp 
(if t 1 (if)) 

(display "12") 

chickenguile都产生一个语法错误。

鸡:

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

sbclclisp两个打印12和发射无警告。

SBCL:

% sbcl --load foo.lisp 
This is SBCL 1.3.11, an implementation of ANSI Common Lisp. 
... 
12 
0]^D 

CLISP

% clisp foo.lisp 

"12" 

回答

8

的Common Lisp的实现:解释器和编译器

Common Lisp中执行代码的类型取决于什么Lisp的系统实现以及你如何使用它。通常,Common Lisp实现有多种方式来执行代码:解释器和一个或多个编译器。即使是一个单一的运行实现可能会有这样的,它将允许用户之间切换。

  • 解释器:直接从Lisp数据结构中执行。它不是像JVM那样的虚拟机代码的解释器。人们不会期望解释器在执行期间验证完整的代码树/图。解释者通常只看到它执行的当前顶层表单。编译器:将Lisp代码编译为C,一些字节代码或机器代码。由于编译器在代码运行之前生成代码,因此它将对它看到的所有代码(可能的例外,请参阅底部的注释)进行语法检查。

  • Toplevel评估:可以使用解释器,编译器或两者的组合。

GNU CLISP同时具有解释器和编译器

实施例在GNU CLISP:

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

[1]> (load "test.lisp") 
;; Loading file test.lisp ... 
;; Loaded file test.lisp 
T 

口译不会检测到错误,因为它不检查整个表达式的语法正确性。由于从句中没有使用带有语法错误的else子句,因此Interpreter将永远不会查看它。

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默认使用一个编译器,其将检测到的错误。对于某些形式的顶级表单使用更简单的评估机制。人们也可以切换到解释器。

如果你写一个简单的IF形式SBCL,评估不使用完全编译和不捕获错误:

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解释,误差不会在定义时检测210

CL-USER> (setf *evaluator-mode* :interpret) 
:INTERPRET 
CL-USER> (defun foo() (if t 1 (if))) 
WARNING: redefining COMMON-LISP-USER::FOO in DEFUN 
FOO 

优化和语法检查

注意某些优化编译器可能不检查可达代码的语法。

摘要

在你需要使用编译器来获得完整的语法警告/错误最常见的Lisp实现。

3

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

R5RS非常得以确认和if它仅规定了使用时的权利,我们已经this passage about error handling做什么:字符串"banana"是一样狡诈和鸡为正确

When speaking of an error situation, this report uses the phrase "an error is signalled" to indicate that implementations must detect and report the error. If such wording does not appear in the discussion of an error, then implementations are not required to detect or report the error, though they are encouraged to do so. An error situation that implementations are not required to detect is usually referred to simply as "an error."

所以,在R5RS包装这件事回应评估(if #t 1 (if))

另一方面R6RS的状态一般为when an exceptional situation is detected by the implementation, an exception is raised。这意味着if与少于两个表达式或多于3个应该引发一个异常,但它并没有说它必须发生编译时间,因为语言可能会解析和解释。