Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Lisp, can you construct a `check-type` that throws an error if the value is not a hash-table with all integer keys and values?

Say I have a function:

(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)))

I want to ensure that at least all the values of the hash-table that are passed in are integers, as I'm using them to repeat values into a big list. Is there any way to do so with check-type before the inner loop? Or would it be good enough practice to let the inner loop macro throw a type error when it tries to repeat a string? (or whatever non integer type)

like image 852
brubsby Avatar asked Dec 17 '25 15:12

brubsby


1 Answers

If you can write a function that can check whether a value is acceptable, then you can use satisfies to construct a type specifier, such as (satisfies is-acceptable). E.g.,

(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)))

With deftype, you can define a type as shorthand for (satisfies all-integer-keys-p), which you may find more readable:

(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))
like image 114
Joshua Taylor Avatar answered Dec 21 '25 05:12

Joshua Taylor