2

宿題のマクロに長い間取り組んでいますが、完全に行き詰っています。先生の時間は限られています。締め切りははるかに過ぎています。これは、これを解決するための最後の試みです。

説明は次のとおりです。

多数のパラメータ pattern_i に対してパラメータ expr を照合するマクロ match-pattern を作成します。成功すると、評価中にバインドされた pattern_i の自由変数で body_i が評価されます。

  • パターンはS式

  • 正確に一致する必要があります

  • 記号引用符は使用できません

  • Expr は 1 回だけ評価する必要があります

    例:

       * (match-pattern '((foo bar) foo baz)
            ((car . car)     `(:cons ,car ,car))
            ((one two three) `(:three ,one ,two ,three)))
    
       (:THREE (FOO BAR) FOO BAZ)
    

これまでの戦術は次のようなものです。

1

パターンを比較するためにマクロで使用する予定の一致関数。(完全に正しくないかもしれませんが、要点はわかります)

    (defun match (sexpr1 sexpr2)
      (cond ((and (consp sexpr1) (consp sexpr2)) 
             (and (match (first sexpr1) (first sexpr2))
                  (match (rest sexpr1)  (rest sexpr2))))
            ((and (atom sexpr1) (atom sexpr2))
             t)
            (t nil)))

2

expr に対してすべてのパターンをループしたいので、それらを match 関数に渡すことで true または nil を返します。true の場合、パターンの本体に expr を割り当てます。

(defmacro match-pattern (sexpr &body body)
  (cond
    ((match sexpr (car (car body))) (print "sexpr shall match with body here"))
    ((null (cdr body)) nil)
    (t `(match-pattern sexpr ,@(cdr body)))))

3

マッチングがどのように機能するのかわかりません。 #'mapcar を無名ラムダ関数と組み合わせて使用​​しようとしましたが、それ以上のことはできませんでした。

これは合理的なアプローチのように思えますか? 引用符で多くの問題を抱えています。説明の例では、expr には引用符がありますが、本文のパターンには引用符がありません。これはなぜですか? そして、なぜボディに :three と :cons があるのでしょうか?

4

2 に答える 2

3

この問題に対する一般的なアプローチは次のとおりです。

  1. マッチャーをより精巧な中間表現に拡張します。たとえば、パターンとアクションのペア(('a b) b)は に変換され(match-action V1 (match-cons (match-quote a) (match-cons (match-bind b) (match-nil))) (progn b))ます。

  2. match-actionコマンドのツリーをネストされたバインドとチェックのシーケンスに展開する、より単純なマクロを実装します。失敗した各チェックは、特別な失敗値を返します。たとえば、(match-action V1 (match-bind x) x)は に展開されます。(let ((x V1)) x)または(match-action V1 (match-cons (match-bind a) (match-bind b)) (cons b a))に展開され(if (listp V1) (let ((V2 (car V1)) (V3 (cdr V1)) (a V2) (b V3)) (cons b a)) match-failure)ます。コマンドは、その引数が既にコンテキスト内にあるかどうかを確認する必要があることに注意してmatch-bindください。この場合、構造的等価性チェックに変換する必要があります。

  3. これで、マクロの実装matchは簡単です。新しい変数を ( でgensym) 導入し、それを式の値にバインドし、マッチャーが と異なるものを返さない限り、マッチャーを順番に適用しますmatch-failure

独自のマッチャーを実装するだけで十分だと思います。このアプローチは拡張可能であることに注意してください。省略記号、関数マッチャー、正規表現など、より複雑なパターンを追加できます。

于 2013-01-20T13:27:49.450 に答える
1

パターン マッチングの質問に答えたことを覚えていますが、機能的な方法で:ワイルド カードを使用してリストを比較します。次の回答は、その回答からコンテキストを保持します。

あなたのマクロは次のようなことをすることができます:

  1. expr一度変数に評価します。
  2. (pattern &body body)句を呼び出しcmp(またはあなたのmatch) に展開し、結果を変数に保持し、非nilの場合は実行しbodyます。

例:

(defmacro match-pattern (expr &rest clauses)
  (let ((expr-var (make-symbol (symbol-name '#:expr)))
        (bindings-var (make-symbol (symbol-name '#:bindings))))
    `(let ((,expr-var ,expr)
           (,bindings-var nil))
       (declare (ignorable ,expr-var))
       (cond ,@(mapcar #'(lambda (clause)
                           (destructuring-bind (pattern &body body)
                               clause
                             `((setf ,bindings-var (cmp ,expr-var ,pattern))
                               (let (,@(mapcar #'(lambda (var)
                                                   `(,var (cdr (assoc ',var ,bindings-var))))
                                               (pattern-vars pattern)))
                                 ,@body))))
                       clauses)))))

これを考えると、次のことを行う必要があります。

  • 定義しpattern-varsます。
  • 一致するパターンに変数がある場合だけでなく、変数バインディングのを返すようにcmp(またはあなたの) を適応させます。matchalistt
于 2013-01-21T17:00:30.483 に答える