对于defmethod和defun,Common Lisp特殊变量范围有什么不同?

Fra*_*ben 2 scope common-lisp

要么我缺少一些非常愚蠢的东西,要么特殊变量的范围对于defmethod和defun意外地不同(使用SBCL 1.1.14测试):

  1. 正如所料:

    (defun ttprint-object (prefix out)
      (format out "~A: in defun: < ~A >~%" prefix *print-readably*))
    (let ((*print-readably* t))
      (format t "let: calling defun: < ~A >~%" *print-readably*)
      (ttprint-object "from let" t))
    
    let: calling defun: < T >
    from let: in defun: < T >
    
    Run Code Online (Sandbox Code Playgroud)
  2. 让defmethod与defun不同,所以出乎意料:

    (defclass empty () ())
    
    (defmethod print-object ((self empty) out)
      (format out "in defmethod: < ~A >~%" *print-readably*)
      (ttprint-object "from defmethod" out))
    
    (let ((*print-readably* t))
      (ttprint-object "from let" t)
      (format t "let: calling defmethod: < ~A >~%" *print-readably*)
      (format t "let: ~A" (make-instance 'empty)))
    
    from let: in defun: < T >
    let: calling defmethod: < T >
    let: in defmethod: < NIL >
    from defmethod: in defun: < NIL >
    
    Run Code Online (Sandbox Code Playgroud)
  3. 同样使用setf defmethod的工作方式与defun不同,但与let相同:

    (progn
      (setq *print-readably* t)
      (ttprint-object "from setf" t)
      (format t "setf: calling defmethod: < ~A >~%" *print-readably*)
      (format t "setf: ~A" (make-instance 'empty)))
    
    from setf: in defun: < T >
    setf: calling defmethod: < T >
    setf: in defmethod: < NIL >
    from defmethod: in defun: < NIL >
    
    Run Code Online (Sandbox Code Playgroud)

希望是我......

先谢谢你,弗兰克

Jos*_*lor 8

~A绑定*print-readably*到错误(强调添加):

22.3.4.1 Tilde A:美学

arg,任何对象,打印时没有转义字符(如princ).如果arg是一个字符串,则其字符将逐字输出.如果arg为零,则将打印为零; 冒号修饰符(〜:A)将导致nil的arg打印为(),但如果arg是复合结构,例如列表或向量,则任何包含的nil出现仍将打印为nil.

...

~A绑定*print-escape*为假,并且*print-readably*为假.

当你这样做

(format t "let: ~A" (make-instance 'empty))
Run Code Online (Sandbox Code Playgroud)

~A指令绑定*print-readably*到false(即nil),最终Lisp编写器调用print-object该对象的方法.如果您不想要此绑定,您可以尝试~W不修改打印机变量:

22.3.4.3 Tilde W:写

参数,任何对象,都是按照每个打印机控制变量打印的(如通过写入).此外,~W通过不将深度计数器重置为零来正确地与深度缩写相互作用.~W不接受参数.如果给出冒号修饰符,~W绑定 *print-pretty*为true.如果给出at-sign修饰符,~W绑定*print-level*并且*print-length*为nil.

~W为检测圆度和共享提供自动支持.如果值*print-circle*不是nil并且~W应用于作为循环(或共享)引用的参数,则在输出中插入适当的#n#标记而不是打印参数.

如果您使用~W,您将获得原先预期的结果:

CL-USER> (let ((*print-readably* t))
               (ttprint-object "from let" t)
               (format t "let: calling defmethod: < ~A >~%" *print-readably*)
               (format t "let: ~w" (make-instance 'empty)))
    from let: in defun: < T >
    let: calling defmethod: < T >
    let: in defmethod: < T >
    from defmethod: in defun: < T >
Run Code Online (Sandbox Code Playgroud)