在 Lisp 中,如果值不是包含所有整数键和值的哈希表,您是否可以构造一个“检查类型”来抛出错误?

bru*_*sby 3 lisp common-lisp

假设我有一个功能:

(defun distribution-to-list (distribution)
  (check-type distribution hash-table)
  (loop for key being each hash-key of distribution
    using (hash-value value) nconc (loop repeat value collect key)))
Run Code Online (Sandbox Code Playgroud)

我想确保至少传入的哈希表的所有值都是整数,因为我使用它们将值重复到一个大列表中。check-type有什么办法可以在内循环之前做到这一点吗?或者让内部循环宏在尝试repeat字符串时抛出类型错误是否足够好?(或任何非整数类型)

Jos*_*lor 5

如果您可以编写一个可以检查某个值是否可接受的函数,那么您可以使用satisfies来构造类型说明符,例如(satisfies is-acceptable)。例如,

(defun all-integer-keys-p (ht)
  (loop for k being each hash-key in ht
        always (integerp k)))

(let ((h (make-hash-table)))
  ;; when the table contains only integer
  ;; keys, we're fine
  (setf (gethash 1 h) 'foo
        (gethash 2 h) 'bar)
  (check-type h (satisfies all-integer-keys-p))

  ;; but a non-integer key will lead to an
  ;; error from CHECK-TYPE
  (setf (gethash 'three h) 'baz)
  (check-type h (satisfies all-integer-keys-p)))
Run Code Online (Sandbox Code Playgroud)

使用deftype,您可以将类型定义为 的简写(satisfies all-integer-keys-p),您可能会发现它更具可读性:

(deftype all-integer-key-hash-table ()
  `(satisfies all-integer-keys-p))

(let ((h (make-hash-table)))
  (setf (gethash 1 h) 'foo
        (gethash 2 h) 'bar)
  (check-type h all-integer-key-hash-table)

  (setf (gethash 'three h) 'baz)
  (check-type h all-integer-key-hash-table))
Run Code Online (Sandbox Code Playgroud)