Scheme 将方案转换为CL

Scheme 将方案转换为CL,scheme,common-lisp,porting,Scheme,Common Lisp,Porting,我对Scheme有点了解(很久以前读过SICP),写了这个程序: (define (prl k m) (define (print-line n) (cond ((> n 0) (display n) (print-line (- n 1))) (else (newline)))) (print-line k) (cond ((> m 1) (prl (+ k 1) (- m 1))))) 示例- 但是我

我对Scheme有点了解(很久以前读过SICP),写了这个程序:

(define (prl k m)
  (define (print-line n)
    (cond ((> n 0) (display n)
                   (print-line (- n 1)))
          (else (newline))))
  (print-line k)
  (cond ((> m 1) (prl (+ k 1) (- m 1)))))
示例-


但是我在CL中需要这个,不使用任何宏。你能帮我实施吗?谢谢。

在这种情况下,从Scheme到CL的转换非常简单:

(defun prl (k m)
  (labels ((print-line (n)
             (cond ((> n 0)
                    (princ n)
                    (print-line (- n 1)))
                   (t (terpri)))))
    (print-line k)
    (cond ((> m 1)
           (prl (+ k 1) (- m 1))))))
用于:


正如雷纳正确指出的那样,奥斯卡的解决方案并不完全正确,因为
defun
在全球环境中定义了一个新功能。这应该是正确的翻译:

(defun prl (k m)
  (labels ((print-line (n)
             (cond ((> n 0)
                    (princ n)
                    (print-line (1- n)))
                   (t (terpri)))))
    (print-line k))
  (when (> m 1)
    (prl (1+ k) (1- m))))
但请注意,与Scheme不同,CL标准并不保证尾部调用优化。您必须检查您的实现文档以了解这一点。

Scheme to Common Lisp

  • 顶层的
    SCHEME:DEFINE
    CL:DEFUN
  • SCHEME:DEFINE
    作为本地定义是
    CL:FLET
    CL:LABELS
  • 默认情况下,CL是非尾部调用优化。这意味着最好使用a)支持TCO的实现并指导编译器这样做,或者b)在必要/可能的情况下使用循环。还要注意,大多数解释器不会在CommonLisp中执行TCO,即使编译器可能支持它
因此,代码将是:

(defun prl (k m)
  (flet ((print-line (n)
           (loop for i downfrom n downto 1 do (write i))
           (terpri)))
    (loop for i from k
          repeat m
          do (print-line i))))
在GOTO语言中,不必有尾部递归保证:

(defun prl (k m)                   ; (define (prl k m)
  (prog (n)
    PRL
      (setf n k)                   ;   (print-line k)
    PRINT-LINE                     ;   (define (print-line n)
      (cond ((> n 0) (princ n)     ;     (cond ((> n 0) (display n)
               (decf n)            ;              (print-line (- n 1)))
               (go PRINT-LINE))
            (t (terpri)))          ;           (else (newline))))
      (cond                        ;   (cond 
        ((> m 1)                   ;    ((> m 1) 
         (incf k)                  ;     (prl (+ k 1) (- m 1)))))
         (decf m) (go PRL)))))
测试:

[19]> (prl 3 4)
321
4321
54321
654321
NIL
[20]> (prl 1 4)
1
21
321
4321
NIL

这是错误的。DEFUN没有像Scheme中定义的那样定义本地函数。@RainerJoswig您有什么建议?将内部定义带到外部?@scar López:公共Lisp中的局部函数由
FLET
标签定义<代码>标签
允许您定义自递归函数。@RainerJoswig谢谢,我不知道CL中的这种
defun
行为。修复了它。@Óscar López:这不是特殊的CL行为。这在Lisp中通常是如此。在Emacs Lisp中甚至没有FLET和标签。您所能做的就是编写顶级函数或使用LET和LAMBDA。另外,CL中的宏在Emacs Lisp中提供FLET和标签。许多语言不支持尾部调用优化,递归仍然很有用。大多数CL实现都部分或完全实现了TCO:@sylvester:print许多行,我们将在没有TCO的情况下得到堆栈溢出许多CL实现都是部分或完全TCO,如果您使用编译器并且优化值设置为这样,那么您需要检查各种限制。如果您使用解释器或类似于在JVM上运行的ABCL的东西,它将无法工作。防御性编程说:避免TCO。是的,你赢了。但实际上,在我得到堆栈溢出之前,我必须得到比我想要的更多的输出(大约7k次调用后Clisp溢出)。在测试了prl的小值后,我为没有(编译“prl”)的人感到羞耻:pOther比Fortran更像,这个版本怎么比Joswig更好?@Sylvester更好?为什么会更好?只是与众不同如何?YMMV,但对于某些人来说,
循环
宏可能比带有显式goto的
prog
更神秘。正如您所知,goto只不过是一个函数调用。反之亦然
prog
是否不是CL规范的一部分?该代码是否与原始方案代码没有更直接的对应关系?
[19]> (prl 3 4)
321
4321
54321
654321
NIL
[20]> (prl 1 4)
1
21
321
4321
NIL