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 |

2007-11-02

Common Idioms (3)

| 15:09 | Common Idioms (3) - わだばLisperになる を含むブックマーク はてなブックマーク - Common Idioms (3) - わだばLisperになる

Brian Mastenbrook氏のCommon Idiomsを拾い読みしてみることの3回目

Common Idioms→CLiki: common-idioms

お題

run-tests

暗記で再現:間違えた

(defmacro run-tests (&rest tests)
  (let ((*print-case* :upcase))
    (with-gensyms (e j)
      `(let ((*print-case* :upcase))
	 (loop for ,j in ',(mapcar (lambda (test) 
				     (cons
				      test
				      (format nil "Test ~A: ~~A~%" test)))
				   tests)
	    for ,e = (apply #'funcall (car ,j))
	    do (format t (cdr ,j) ,e)
	    collect ,e)))))
;; 正解
(defmacro run-tests (&rest tests)
  "Run the functions named by the supplied TESTS (not evaluated),
printing and collecting their values."
  (let ((*print-case* :upcase))
    (with-gensyms (e j)
      `(let ((*print-case* :upcase))
         (loop for ,e in (list ,@(mapcar #'(lambda (test) (list 'cons `(function ,test) (format nil "Test ~A: ~~A~%" test))) tests))
            for ,j = (funcall (car ,e))
            do (format t (cdr ,e) ,j)
            collect ,j)))))

間違えた。テストの関数を実行するものだったのに式を実行するものと勘違いして随分悩んだ。(apply #'funcall)などとしているのはそのため。

;; 動作
(run-tests (lambda() (print "foo"))
	   (lambda() (print "bar"))
	   (lambda() (print "zot")))

=>
;Test (LAMBDA () (PRINT foo)): foo
;Test (LAMBDA () (PRINT bar)): bar
;Test (LAMBDA () (PRINT zot)): zot

お題

macroexpand-n

暗記で再現:間違えた

(defmacro macroexpand-n (n expr)
  (if (eql n 1)
      `(macroexpand-1 ,expr)
      `(macroexpand-1 (macroexpand-n ,(1- n) ,expr))))

;; 正解
(defmacro macroexpand-n (n form)
  "MACROEXPAND-1 FORM recursively N times."
  (if (eql n 1)
      `(macroexpand-1 ,form)
      `(macroexpand-n ,(1- n) (macroexpand-1 ,form))))

間違えた。再帰の部分で入れ子の順番を間違えた。しかし結果は一緒なんだけれど、これら2つ詳細な動作がどう違うのか/違わないのか、良く分からない…。

;; 動作
(defmacro pg (arg &rest body)
  `(prog (,arg)
      ,@body))

(macroexpand-n 1 '(pg () (print "hello")))
=>
(PROG (NIL) (PRINT "hello")) 

(macroexpand-n 2 '(pg () (print "hello")))
=>
(BLOCK NIL
  (LET (())
    (TAGBODY (PRINT "hello"))))