🚀

M-99 マクロ定義課題99問

2024/04/14に公開

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