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-01-19

俺Arc祭り 2008冬 (2)

| 00:18 | 俺Arc祭り 2008冬 (2) - わだばLisperになる を含むブックマーク はてなブックマーク - 俺Arc祭り 2008冬 (2) - わだばLisperになる

だらだら続いております。俺Arc祭り。

自分の書いているものが、非常に読み辛く、また書いてても良く分からなくなって来たので、小分けにして行くことにしました。

8. Functions and Macro

  • fn

lambdaは、fnと書くそうです。


(macro fn body
  `(cl:lambda ,@body))

非常に安直に…。(funcall (fn (x) (+ x 3)) 3)としないと動きません…。

((fn (x) (+ x 3) ) 3)みたいにして動くようにする簡単な方法ってあるんでしょうか。

  • rfn

labels(再帰可能なローカル関数定義)は、rfnと書くとのこと。

rfnは、多分トップレベルでも使えるんだろうとは思いますが、色々大変そうなので、doに埋め込むことにしました。

段々と定義するのにパッケージを指定するのが面倒になってきたので、my-arcパッケージを定義するために、my-arc-defというパッケージを作成し、そこからインポートすることにしてみます。

  • no

doの例で出てきたので、nullの一般化されたものと勝手に解釈して適当に定義。


;; 動作
(do (= x '(foo bar baz))
    (rfn len (x) (if (no x) 0 (+ 1 (len (cdr x)))))
    (pr 1)
    (rfn fact (n) (if (no n) 1 (* n (fact (1- n)))))
    (pr 2)
    (= y (len x))
    (list x y (fact 10)))

;->1 2
;=> ((FOO BAR BAZ) 3 3628800)

;; 上記のマクロ展開
(let (y x)
     (declare (ignorable y x))
     (setq x '(foo bar baz))
     (labels ((len (x)
		(let ((it (no x)))
		     (if it 0 (+ 1 (len (cdr x))))))
	      (fact (n)
		(let ((it (no n)))
		     (if it 1 (* n (fact (1- n)))))))
       (pr 1)
       (pr 2)
       (setq y (len x))
       (list x y (fact 10))))

;; ごちゃごちゃ定義
(in-package :my-arc-def)

(defun rfn-expander (body)
  (do ((b body (cdr b)) res)
      ((endp b) (nreverse res))
    (if (eq 'rfn (alexandria:ensure-car (car b)))
	(multiple-value-bind (fn bo) (rfn+body b)
	  (return `(,@(nreverse res)
		      (labels ,fn
			,@bo))))
	(push (car b) res))))

(defun rfn+body (body)
  (let (fn bo)
       (dolist (b body (values (nreverse fn)
			       (nreverse bo)))
	 (if (eq 'rfn (car b))
	     (push (cdr b) fn)
	     (push b bo)))))

(in-package :my-arc)

(macro do body
  (let vars (x-finder '= body)
    `(cl:let ,vars
	  (declare (ignorable ,@vars))
	  ,@(rfn-expander
	     body))))

(defmethod no ((obj null)) t)
(defmethod no ((obj string)) (equal obj ""))
(defmethod no ((obj character)) (equal obj #\Nul))
(defmethod no ((obj number)) (zerop obj))
(defmethod no ((obj vector)) (equalp obj #()))
(defmethod no (obj) nil)

  • マクロはファーストクラスオブジェクト

局所マクロを作るのは単に変数に束縛するだけ。

これは無理なのでスルー。

しかし、マクロがファーストクラスオブジェクトだとどういう風にプログラミングスタイルが変わるんでしょうね。

例示されているmacroの例なんですが、


(macro (test . body)
  `(if ,test (do ,.body))) 

;; when?
(macro when (test . body)
  `(if ,test (do ,.body)))

;; 動作
(when 33
  'foo 'bar 'baz it)
;=> 33

これってタイポでwhenが抜けてるんですかね? whenだと合点が行くのですが…。

ひたすら続きます…。