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

时间:2014-01-28 20:17:17

标签: common-lisp scope

要么我缺少非常愚蠢的东西,要么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 >
    
  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 >
    
  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 >
    
  4. 希望是我......

    先谢谢,弗兰克

1 个答案:

答案 0 :(得分:8)

~A*print-readably*绑定为false(强调添加):

  

22.3.4.1 Tilde A: Aesthetic

     

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

     

...

     

~A*print-escape*绑定为false,将*print-readably*绑定为false。

当你这样做时

(format t "let: ~A" (make-instance 'empty))

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

  

22.3.4.3 Tilde W: Write

     

参数,任何对象,都是按照每个打印机控件打印的   变量(通过写入)。另外,~W与深度正确地相互作用   缩写,通过不将深度计数器重置为零。 ~W没有   接受参数。如果给出结肠修饰符,~W结合   *print-pretty*为真。如果给出了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 >