2

我正在编写一个 Lisp 程序,并试图对类型有点认真。我想有性能改进,但我对使用类型注释来记录和安全更感兴趣。问题是nil。到目前为止,我遇到了两个问题。

展品 A:

>(defmethod foo ((bar bar-class) (quux quux-class))
   ...)

>(foo (make-instance 'bar-class) nil)
 ERROR: No applicable method, etcetera etcetera, because nil is not of type quux-class

展品 B:

(defmethod initialize-instance :after ((f foo) &rest args)
  "Initialize the grid to be the right size, based on the height and width of the foo."
  (declare (ignorable args))
  (setf (slot-value f 'grid) (make-array (list (width f) (height f))
                                         :element-type 'foo-component
                                         :adjustable nil
                                         :initial-element nil)))

style-warning: 
  NIL is not a FOO-COMPONENT.

这里的最佳做法是什么?到目前为止,我唯一有远见的想法是使用空对象模式并拥有(defclass nil-quux-class (quux-class) ...)and (defclass nil-foo-component (foo-component) ...),但这似乎充其量是 hacky。我不知道为什么,但确实如此。坦率地说,我不习惯在 CLOS 中设计模式变通方法 :)

4

2 回答 2

6

(A) 当你呼吁 争论foo时,你希望发生什么?nilquux

如果你什么都不想发生,那么

(defmethod foo ((bar bar-class) (quux null))
  nil)

会给你整理的。

如果您希望调用相同的代码,就好像您传递了 的实例一样quux-class,那么:

(defmethod foo ((bar bar-class) (quux quux-class))
  (do-stuff bar quux))

(defmethod foo ((bar bar-class) (quux null))
  (do-stuff bar quux))

或者:

(defmethod foo ((bar bar-class) quux)
  (unless (or (typep bar 'bar-class)
              (null bar))
    (error "Expected a bar-class or null, got ~s." quux))
  (do-stuff bar quux))

(B) 你走了

(make-array size :element-type 'foo-component
                 :initial-element nil)

并且您的 lisp 实现指出了一个矛盾 - 初始元素不能同时是nilfoo-components。(嗯,我想这取决于你的类型foo-component。我假设它不包括null。)

你可能会考虑:

(make-array :element-type '(or foo-component null)
            :initial-element nil)

但请注意:您希望您的 lisp 从知道数组将包含foo-components 或nils 中获得什么?优化?代表您检查错误?(根据您使用的 lisp 实现,您的里程可能会有所不同。)

于 2013-07-05T16:48:48.713 回答
4

请注意,a 的元素类型MAKE-ARRAY不是真正的类型声明。这是对 Lisp 实现的一个提示,数组应该能够存储什么样的数据。然后它可能会选择或不选择专门的数组实现。

UPGRADED-ARRAY-ELEMENT-TYPE返回能够保存由 typespec 表示的类型的最专业数组表示的元素类型。

CL-USER 12 > (upgraded-array-element-type '(integer 0 100))
(UNSIGNED-BYTE 8)

上面的意思是我请求一个包含 0 到 100 之间整数元素的数组。这个 Lisp(这里是 LispWorks)会给我一个元素类型为 的数组(unsigned-byte 8)

更多示例:

CL-USER 13 > (upgraded-array-element-type 'fixnum)
(SIGNED-BYTE 64)

CL-USER 14 > (upgraded-array-element-type 'complex)
T

CL-USER 15 > (defclass foo-component () ())
#<STANDARD-CLASS FOO-COMPONENT 402030196B>

CL-USER 16 > (upgraded-array-element-type 'foo-component)
T

T这里的意思是数组实际上会存储各种数据对象。

CL-USER 17 > (upgraded-array-element-type '(or null foo-component))
T

CL-USER 20 > (make-array 2
                         :element-type 'foo-component
                         :initial-element (make-instance 'foo-component))
#(#<FOO-COMPONENT 40203B9A03> #<FOO-COMPONENT 40203B9A03>)

CL-USER 21 > (array-element-type *)
T

上面显示 Lisp 也忘记了最初请求的内容。我们实际上得到了一个 element-type 数组,T当我们询问它的 element-type 时,它​​就是T.

于 2013-07-05T17:28:41.170 回答