🚀
M-99 マクロ定義課題99問
M-99 マクロ99問
(解答例: R6RS Common Lispその他 Common Lisp)
与えられた引数を全てQUOTEしてリストとして返すLISTQを作成せよ
テーマ:引数のクォート
(listq a b c d e)
≡ (list 'a 'b 'c 'd 'e)
;=> (A B C D E)
INC1を作成せよ
テーマ:変数の捕捉
(let ((x 0))
(inc1 x)
x)
≡ (let ((x 0))
(setq x (+ x 1)))
;=> 1
Common LispのWHENを作成せよ
テーマ:制御構文の自作
(my-when (< 1 2)
(print "hello"))
;->
; "hello"
;=> "hello"
Common LispのUNLESSを作成せよ
テーマ:制御構文の自作
(my-unless (> 1 2)
(print "hello"))
;->
; "hello"
;=> "hello"
条件が真の間だけボディ内を繰り返すWHILEを作成せよ
テーマ:繰り返し構文の自作
(let ((i 0))
(while (< i 10)
(print i)
(incf i)))
;->
; 0
; 1
; 2
; 3
; 4
; 5
; 6
; 7
; 8
; 9
;=> NIL
条件が偽の間だけボディ内を繰り返すUNTILを作成せよ
テーマ:繰り返し構文の自作
(let ((i 10))
(until (< i 0)
(print i)
(decf i)))
;->
; 10
; 9
; 8
; 7
; 6
; 5
; 4
; 3
; 2
; 1
; 0
;=> NIL
ボディの中身を無限に繰り返すDO-FOREVERを作成せよ。
なおボディ内からは、RETURNで脱出できるようにせよ。
テーマ:繰り返し/脱出
(do-forever
(print "hello!")
(return))
≡ (block nil
(tagbody
#:g1
(print "hello!")
(return)
(go #:g1)))
;->
; "hello!"
;=> NIL
INC1を拡張したINCを作成せよ
INCはINC1と違い増加する量を引数で指定できる。
テーマ:変数の捕捉
(let ((x 0))
(inc x)
x)
≡ (let ((x 0))
(setq x (+ x 1)))
;=> 1
(let ((x 0))
(inc x 2)
x)
;=> 2
Common LispのANDを作成せよ
テーマ:制御構文の自作
(my-and 1 2 3 nil 4)
;=> nil
(my-and 1 2 3 t 4)
;=> 4
Common LispのORを作成せよ
テーマ:制御構文の自作
(my-or 1 2 3 nil 4)
;=> 1
(my-or nil nil nil 4)
;=> 4
LAMBDAを用いてLETを作成せよ
テーマ:束縛構文の自作
(my-let ((a 1)
(b 2))
(list a b))
≡ ((lambda (a b) (list a b)) 1 2)
;=> (1 2)
LAMBDAを用いてLET*を作成せよ
テーマ:束縛構文の自作
(my-let* ((a 1)
(b a))
(list a b))
≡ ((lambda (a)
((lambda (b)
(list a b)) a)) 1)
;=> (1 1)
Common LispのCONDを作成せよ
テーマ:制御構文の自作
Common LispのPSETQを作成せよ:
テーマ:構文の自作
LAMBDAを用いてLETを作成せよ(拡張形式):
テーマ:構文の自作
(my-let ((a 1)
(b) ;NILで初期化される
c) ;NILで初期化される
(list a b c))
≡ ((lambda (a b c) (list a b c)) 1 nil nil)
;=> (1 NIL NIL)
LAMBDAを用いてLET*を作成せよ(拡張形式):
テーマ:構文の自作
(my-let* ((a 1)
(b a)
(c) ;NILで初期化される
d) ;NILで初期化される
(list a b c d))
≡ ((lambda (a)
((lambda (b)
((lambda (c)
((lambda (d)
(list a b c d))
nil)) nil)) a)) 1)
;=> (1 1 NIL NIL)
Common LispのDOLISTを作成せよ
テーマ:構文の自作
Common LispのDOTIMESを作成せよ
テーマ:構文の自作
MULTIPLE-VALUE-CALLから MULTIPLE-VALUE-BINDを作成せよ
テーマ:構文の自作
アナフォリックマクロ AIF を作成せよ
テーマ:構文の自作/変数の捕捉
...
...
...
Common LispのCASEを作成せよ
テーマ:構文の自作
アナフォリックマクロ AAND を作成せよ
テーマ:構文の自作
...
テーマ:構文の自作
TAOのLOOP構文を作成せよ
テーマ:構文の自作
<説明>
形式 : loop [exit-id] [(&aux var ...)]
[(:init init-form ...)]
[(:until pred exit-form1 exit-form2 ...)]
[(:while pred exit-form1 exit-form2 ...)]
form1 form2 ... formN
TAO の基本的な繰り返しの機能。
&aux で loop の中だけで有効な補助変数を宣言する。
:init があれば init-form を最初に一度だけ評価する。
:until の述語が成立するか、または :while の述語が成立しなくなるまで
form1 form2 ... を順に評価する。そして、:until 文が成立、または :while
文が成立しなくなった時、対応する exit-form1 ... を順に評価して loop
から抜け、最後の exit-form の値を返す。
:until や :while は何回でも使えるし省略可能。 exit-form は省略可能。
(defun f (n)
(loop (&aux c result)
(:init (setq c 0 result 1))
(:until (= c n) result)
(setq result (* (incf c) result))))
;; loop内部からは、exit-loopで脱出することができる
(loop abc (&aux x y) ;exit-id = abc
(:init (setq x 0)) ;初期化節
;; ループ本体
(setq x (1+ x))
(setq y (+ (expt x 3) (expt x 2) x 1))
(cond ((<= y 50) (print y))
(t
;; (返り値[省略可能/省略時はNILとする] exit-id[省略可能])
(exit-loop 'end abc))))
-> 4
15
40
end
ONCE-ONLYを作成せよ
テーマ:構文の自作/変数の捕捉
...
...
...
...
Common LispのWITH-OPEN-FILEを作成せよ
テーマ:構文の自作/例外発生時の対応
Common LispのINCFを作成せよ
テーマ:F(ield)系マクロの値の扱い
(let ((a #(1 2 3 4)))
(my-incf (aref a 0) 10)
a)
;=> #(11 2 3 4)
簡易テストフレームワークを作成せよ
テーマ:DSL
仕様:
...
...
...
...
...
...
...
分配束縛機能付きのLETを作成せよ
テーマ:構文の自作
(dlet (((a . b) (1 2 3 4))
(c 5)
(d)
e)
(list a b c))
;=> (1 (2 3 4) 5 NIL NIL)
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
Common Lispのdestructuring-bindを作成せよ
テーマ:構文の自作
...
...
...
...
...
...
...
...
...
...
...
...
...
パターンマッチで分配束縛するMATCHマクロを作成せよ
テーマ:構文の自作
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
ANSI Common LispのLOOPを作成せよ
テーマ:DSL
...
...
...
...
...
...
...
候補と議論
容易
↑
- comment
- let1
- when-let
- srfi-31
- srfi-26
- srfi-87
- srfi-61
- srfi-2 and-let*
- srfi-42
↓
難解(難しい/面倒臭い)
種別
- setfマクロ
- コンパイラマクロ
- コードウォーカーが必要なマクロ(my-setq)
- リーダーマクロ
Discussion