M-99


M-99 マクロ99問

(解答例: R6RS Common Lispその他 Common Lisp)

  1. 与えられた引数を全てQUOTEしてリストとして返すLISTQを作成せよ
    テーマ:引数のクォート
    (listq a b c d e)
    ≡ (list 'a 'b 'c 'd 'e)
    ;=> (A B C D E)
    
  2. INC1を作成せよ
    テーマ:変数の捕捉
    (let ((x 0))
      (inc1 x)
      x)
    ≡ (let ((x 0))
         (setq x (+ x 1)))
    ;=> 1
    
  3. Common LispのWHENを作成せよ
    テーマ:制御構文の自作
    (my-when (< 1 2)
      (print "hello"))
    ;->
    ;   "hello"
    ;=> "hello"
    
  4. Common LispのUNLESSを作成せよ
    テーマ:制御構文の自作
    (my-unless (> 1 2)
      (print "hello"))
    ;->
    ;   "hello"
    ;=> "hello"
    
  5. 条件が真の間だけボディ内を繰り返すWHILEを作成せよ
    テーマ:繰り返し構文の自作
    (let ((i 0))
      (while (< i 10)
        (print i)
        (incf i)))
    ;->
    ;   0
    ;   1
    ;   2
    ;   3
    ;   4
    ;   5
    ;   6
    ;   7
    ;   8
    ;   9
    ;=> NIL
    
  6. 条件が偽の間だけボディ内を繰り返すUNTILを作成せよ
    テーマ:繰り返し構文の自作
    (let ((i 10))
      (until (< i 0)
        (print i) 
        (decf i)))
    ;-> 
    ;   10 
    ;   9 
    ;   8 
    ;   7 
    ;   6 
    ;   5 
    ;   4 
    ;   3 
    ;   2 
    ;   1 
    ;   0 
    ;=> NIL
    
  7. ボディの中身を無限に繰り返すDO-FOREVERを作成せよ。
    なおボディ内からは、RETURNで脱出できるようにせよ。
    テーマ:繰り返し/脱出
    (do-forever
      (print "hello!")
      (return))
    ≡ (block nil
         (tagbody 
           #:g1
           (print "hello!")
           (return)
           (go #:g1)))
    ;->
    ;   "hello!"
    ;=> NIL
    
  8. 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
    
  9. Common LispのANDを作成せよ
    テーマ:制御構文の自作
    (my-and 1 2 3 nil 4)
    ;=> nil
    
    (my-and 1 2 3 t 4)
    ;=> 4
    
  10. Common LispのORを作成せよ
    テーマ:制御構文の自作
    (my-or 1 2 3 nil 4)
    ;=> 1
    
    (my-or nil nil nil 4)
    ;=> 4
    
  11. LAMBDAを用いてLETを作成せよ
    テーマ:束縛構文の自作
    (my-let ((a 1)
             (b 2))
      (list a b))
    ≡ ((lambda (a b) (list a b)) 1 2)
    ;=> (1 2)
    
  12. LAMBDAを用いてLET*を作成せよ
    テーマ:束縛構文の自作
    (my-let* ((a 1)
              (b a))
      (list a b))
    ≡ ((lambda (a)
          ((lambda (b)
             (list a b)) a)) 1)
    ;=> (1 1)
    
  13. Common LispのCONDを作成せよ
    テーマ:制御構文の自作
  14. Common LispのPSETQを作成せよ:
    テーマ:構文の自作
  15. 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)
    
  16. 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)
    
  17. Common LispのDOLISTを作成せよ
    テーマ:構文の自作
  18. Common LispのDOTIMESを作成せよ
    テーマ:構文の自作
  19. MULTIPLE-VALUE-CALLから MULTIPLE-VALUE-BINDを作成せよ
    テーマ:構文の自作
  20. アナフォリックマクロ AIF を作成せよ
    テーマ:構文の自作/変数の捕捉
  21. Common LispのCASEを作成せよ
    テーマ:構文の自作
  22. アナフォリックマクロ AAND を作成せよ
    テーマ:構文の自作
  23. テーマ:構文の自作
  24. 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 (exit-loop 'end abc)))) ; (返り値[省略可能/省略時はNILとする] exit-id[省略可能])
    -> 4
       15
       40
       end
    
  25. ONCE-ONLYを作成せよ
    テーマ:構文の自作/変数の捕捉
  26. Common LispのWITH-OPEN-FILEを作成せよ
    テーマ:構文の自作/例外発生時の対応
  27. Common LispのINCFを作成せよ
    テーマ:F(ield)系マクロの値の扱い
    (let ((a #(1 2 3 4)))
      (my-incf (aref a 0) 10)
      a)
    ;=> #(11 2 3 4)
    
  28. 簡易テストフレームワークを作成せよ
    テーマ:DSL
    仕様:
    
  29. 分配束縛機能付きのLETを作成せよ
    テーマ:構文の自作
    (dlet (((a . b) (1 2 3 4))
           (c 5)
           (d)
           e)
      (list a b c))
    ;=> (1 (2 3 4) 5 NIL NIL)
    
  30. Common Lispのdestructuring-bindを作成せよ
    テーマ:構文の自作
  31. パターンマッチで分配束縛するMATCHマクロを作成せよ
    テーマ:構文の自作
  32. ANSI Common LispのLOOPを作成せよ
    テーマ:DSL

候補と議論

容易 ↑

↓ 難解(難しい/面倒臭い)

種別

参考


Last modified : 2011/02/16 08:19:40 JST
CC0 1.0
Powerd by WiLiKi 0.6.1 on Gauche 0.9