#:g1: thenretの活用

Posted 2020-09-19 23:44:52 GMT

古えのLucid CLのソースを眺めていて、こんなコードに遭遇したのですが、これがなかなか味わい深い。
コードの作者はJonL氏。

(defun find-named-slot (slot-name slotds &optional (no-error-p nil))
  (cond ((loop for slotd in slotds
               thereis (and (eq slot-name (%slotd-name slotd))
                            slotd)))
        (no-error-p nil)
        (t (system-error hhctb))))

condの述語部の返り値を活用しているのですが、Franz Lispのifでいうthenretの活用です。

実際に最近の処理系でも動くように書き直すと下記のようになるでしょうか。
(ついでにloopthereisfindに置き換え)

(ql:quickload "closer-mop")
(in-package c2cl)

(defun find-named-slot (slot-name slotds &optional (no-error-p nil)) (cond ((find slot-name slotds :key #'slot-definition-name)) (no-error-p nil) (t (error "How the hell can this be?!"))))

(defclass foo () (a b c))

(find-named-slot 'a (class-slots (find-class 'foo))) → #<standard-effective-slot-definition a 411021F02B>

(find-named-slot 'z (class-slots (find-class 'foo))) >> Error: How the hell can this be?!

ちなみに、hhctbは、MACLISPのエラーコードで、“How the hell can this be?!”の略みたいです。
色々検索してもヒットしないので、もしかするとJonL氏以外使ってないんじゃないでしょうか。

上記をifの連鎖で書くと下記のようになります。

(defun find-named-slot (slot-name slotds &optional (no-error-p nil))
  (let ((slotd (find slot-name slotds :key #'slot-definition-name)))
    (if (not (null slotd))
        slotd
        (if no-error-p
            nil
            (error "How the hell can this be?!")))))

ifで書き直してみると、no-error-pのあたりも含めて、thenretだけでなくcondを上手く活用していることが分かります。

thenretに類似するところでは、orの返り値を活用するというのがありますが、慣れないと少し解読が難しいかも。

(defun find-named-slot (slot-name slotds &optional (no-error-p nil))
  (let ((slotd (find slot-name slotds :key #'slot-definition-name)))
    (or slotd
        (and (not no-error-p)
             (error "How the hell can this be?!")))))

ちなみにrmsのLispコードではこういうパタンが多用されています。

まとめ

伝統的なLispでの thenret は多値を返さない(せない)のですが、srfi-61では、多値を活かすことができる仕組みになっています。

(cond ((values 0 1) values => values)
      (else #f))

アナフォリックマクロのitwhen-let等もthenretの文脈に近いものがありますが、慣れると結構活用できる気がします。


HTML generated by 3bmd in LispWorks Personal Edition 7.1.2

comments powered by Disqus