1

ifブール論理とマクロを使用して独自のものを書きたかったのです。私は次の実装を思いつきました:

(defmacro -if (condition if-true if-false)
  "Implements `if` in terms of Boolean logic only"
  `(or (and ,condition ,if-true)
       (and (not ,condition) ,if-false)))

いくつかのケースで手動でテストしましたが、期待どおりに動作します。しかし、一連のテストを実行するための簡単なテスト関数を書いたところ、まだ理解できない結果が 1 つ得られました。私は次のように関数を書きました:

(defun -if-test ()
  (let ((passed 0)
    (test-format "TEST: ~50a ==> ~:[FAILURE~;SUCCESS~]~%")
    (cases '((return-value (> 2 1) true)
         (return-value (< 2 1) false)
         (standard-output (> 2 1) "true")
         (standard-output (< 2 1) "false"))))
    (dolist (test-case cases)
      (destructuring-bind (type test expected) test-case
    (let ((result (case type
            (return-value
             (eq (-if test 'true 'false) expected))
            (standard-output
             (with-output-to-string (out)
               (string= (-if test (print "true" out) (print "false" out)) expected)))
            (otherwise (error "Unknown test type: ~a" type)))))
      (when result (incf passed))
      (format t test-format test-case result))))
    (format t "Result: ~a/~a tests passed.~%" passed (length cases))))

テストを実行すると、次の出力が得られます。

TEST: (RETURN-VALUE (> 2 1) TRUE)                        ==> SUCCESS
TEST: (RETURN-VALUE (< 2 1) FALSE)                       ==> FAILURE
TEST: (STANDARD-OUTPUT (> 2 1) true)                     ==> SUCCESS
TEST: (STANDARD-OUTPUT (< 2 1) false)                    ==> SUCCESS
Result: 3/4 tests passed.
NIL

2 番目の失敗例は、手動で実行した場合と、この関数の一部として実行した場合で明らかに異なる結果になります。SLDB でデバッグしてみましたが、実際にスタンドアロンで実行した場合とは結果が異なります。重要な実行の詳細などを見逃していたのではないかと思います。誰かがここで何が起こっているのか説明できますか? 助けて本当に感謝しています。

PS私の実装はClozure CLです。

4

2 に答える 2

2

テスト ケースはデータです。あなたがフィードする-ifのは評価ではなく、要素として,とを含む(< 2 1)リストです。それ以外は真理値なので、テストしたい場合は次を試してください。<21nil(-if '(< 2 1) 'true 'false) ;==> true

したがって、この場合、テストに問題がありました。ただし、マクロにエラーがあります。

(-if (progn (print "ONLY ONE TIME!") x) nil t)
; ==> (not x), but it prints "ONLY ONE TIME!" twice!

マクロを作成するときは、引数が 1 回だけ評価されること、評価される順序が引数の順序になっていることを常に確認する必要があります。最後の 1 つは、gensym衛生を確保するための使用を求めます。

マクロ エラーを修正するには、述語を評価する let フォームに展開して、副作用が 2 回行われないようにする必要があります。この変数の名前は、好きな本や有名な本からの を使用する やマクロで一意にする必要がありgensymます。優れた本はPractical Common Lispで、無料で読むことができ、マクロと一般的なエラーとその修正方法に関する部分がありますgensymonly-oncewith-gensyms

于 2014-05-20T10:50:57.537 に答える