2017-02-17 4 views
0

マクロを使用してHeap's algorithmを実装しました。それは正常に動作していますが、必要に応じてアナフォリックまたは非アナフォリックコードを生成するように調整したいと思います。言い換えれば、私は、マクロがシーケンスの内部コピーを作成するか、マクロの外部で利用可能なシーケンスに対して作業をしたいと思っています。 ...&keyと&restをlispマクロのラムダリストに組み合わせる最良の方法は何ですか?

;; Anaphoric version 
;; To make it non-anaphoric, substitute (,var (copy-seq ,vec)) for (,var ,vec) 
(defmacro run-permutations (var vec &rest body) 
"Executes body for all permutations of vec, which is stored in variable var" 
    `(let ((,var ,vec)) 
    (labels ((generate (&optional (n (length ,var))) 
     (if (= n 1) 
     (progn ,@body) 
     (progn 
      (loop for i from 0 below (1- n) 
       do (progn 
         (generate (1- n)) 
         (rotatef (aref ,var (if (evenp n) i 0)) 
           (aref ,var (1- n))))) 
      (generate (1- n)))))) 
     (generate)))) 

? (run-permutations v "123" (pprint v)) 
"123" 
"213" 
"312" 
"132" 
"231" 
"321" 
? 

私はこのように働いた何かを書きたい

? (setf v "123") 
? (run-permutations :anaphoric t v "123" (...do stuff...)) 
? v 
"321" 

? (setf v "123") 
? (run-permutations v "123" (...do stuff...)) 
? v 
"123" 

...しかし、私は見つかっていない。

私は全く不十分で、実に恥ずかしいコードがあります&rest&keyまたはラムダリストを書くための他の方法の満足できる組み合わせ。

私の質問です:マクロのラムダリストを解析するコードを書かずに、これを達成する方法がありますか?あるいは、もう少し標準的な(そしておそらくよりエレガントな)ソリューションがありますか?私は後者を強く疑う。

あなたのご意見は大変ありがとうございます。いつものように、コードに関する他のコメントも高く評価されています。

UPDATE

ブリリアント! bodyが再帰の中から呼び出されていて、どこからでも呼び出すことができないため、ngensymを使用することを選択しました。少なくとも、すべてを書き直すことはありませんでした。

また、別の機能とマイナーな最適化を追加しました。あなたは好奇心旺盛だ場合は、更新されたバージョンは次のとおりです。

(defmacro do-permutations ((var vec &key anaphoric (len (length vec))) &body body) 
    "Executes body for all permutations of vec, which is stored in variable var. 
    KEYS: 
    anaphoric: if defined, modifies var outside the macro, preserves it otherwise 
    len: number of items that will be permuted, default is the full vector" 
    (let ((n (gensym))) 
    `(let ((,var ,(if anaphoric vec `(copy-seq ,vec)))) 
    (labels ((generate (&optional (,n ,len)) 
       (if (= ,n 1) 
        (progn ,@body) 
        (let ((n-1 (1- ,n))) 
        (loop for i from 0 below n-1 
          do (progn 
           (generate n-1) 
           (rotatef (aref ,var (if (evenp ,n) i 0)) 
             (aref ,var n-1)))) 
        (generate n-1))))) 
     (generate))))) 

最後に、私はdoprognを削除しようとしたが、2式はその点で評価する必要があるので、それは動作しませんでした。正しく

答えて

4

インデントあなたのコードを:マクロで

(do-permutations (v "123" :anaphoric t) 
    (some) 
    (stuff)) 

(defmacro run-permutations (var vec &rest body) 
    "Executes body for all permutations of vec, which is stored in variable var" 
    `(let ((,var ,vec)) 
    (labels ((generate (&optional (n (length ,var))) 
       (if (= n 1) 
        (progn ,@body) 
        (progn 
        (loop for i from 0 below (1- n) 
          do (progn 
           (generate (1- n)) 
           (rotatef (aref ,var (if (evenp n) i 0)) 
             (aref ,var (1- n))))) 
        (generate (1- n)))))) 
     (generate)))) 

使用のようなもの

(defmacro do-permutations ((var vec &key anaphoric) &body body) 
    ...) 

他の名前:doing-permutationswith-permutations、...

&restではなく、&bodyで本文を宣言できることにも注意してください。セマンティクスは同じですが、インデントが異なると予想されます。 &bodyは、Lispフォームのリストが続くことを知らせます。

doの後にloopprognも必要ありません。

bodyは、変数nを表示します。あなたは体の別の場所を考えるかもしれません...

+0

あなたは正しいインデントの参照を知っていますか?私はemacsのデフォルト書式を使用していて、代替案に興味があります。 –

+1

@JonChesterfield:ここをクリック:http://emacs.stackexchange.com/questions/30788/why-does-emacs-indent-my-lisp-loop-construct-weirdly –

+0

ありがとう! slime-cl-indentはよく見えます。 –

関連する問題