Hatena::Groupcadr

わだばLisperになる このページをアンテナに追加 RSSフィード

2004 | 12 |
2005 | 01 | 02 | 07 | 10 | 11 |
2006 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 11 |

2008-10-25

Cyan風のif

| 03:10 | Cyan風のif - わだばLisperになる を含むブックマーク はてなブックマーク - Cyan風のif - わだばLisperになる

デフォルトでif-let風味なCyanのifが面白いので、CLのマクロで真似してみました。

2種類考えたのですが、letのバインド部をそのまんまifの判定のところに埋め込んでしまったバージョンのcifと、代入的な構文の時のみif-letに展開されて普通の場合はifになるというcif2です。

やはり、変数が複数になった場合どうするんだろうねという感じなのですが、cifは全部のandをとる、cif2は、変数1つということにしました。

ちなみに、if-letとの違いですが形がちょっと違ってるだけです(笑)

;;; cif
(eval-when (:compile-toplevel :load-toplevel :execute)
  (defun car-or-atom (obj)
    (if (consp obj)
      (car obj)
      obj)))

(defmacro cif (pred con &optional alt)
  (let ((vars (mapcar #'car-or-atom pred)))
    `(let ,pred
       (declare (ignorable ,@(remove nil vars)))
       (if (and ,@vars)
           ,con
           ,alt))))

;; 動作
(cif ((x "そのとおり") (y t) (z (zerop (random 2))))
     (format t "はい~A~%" x)
     (format t "いいえ~%"))
;=> はいそのとおり(ランダム)

;;; cif2
(eval-when (:compile-toplevel :load-toplevel :execute)
  (defun cif-bind-p (obj)
    (and (consp obj)
         (= 3 (length obj))
         (string-equal "=" (second obj)))))
  
(defmacro cif2 (pred con &optional alt)
  (if (cif-bind-p pred)
      `(let ((,(first pred) ,(third pred)))
         (cif2 ,(first pred) ,con ,alt))
      `(if ,pred ,con ,alt)))

;; 動作
(cif2 (x := "そのとおり")
      (format t "はい~A~%" x)
      (format t "いいえ~%"))
;=> はいそのとおり

(cif2 "そのとおり"
      (format t "はい~%")
      (format t "いいえ~%"))
;=> はい