1

行列を操作する 3 つの関数があるとします。

(defn flip [matrix] (...))
(defn rotate [matrix] (...))
(defn inc-all [matrix] (...))

各関数が正しく機能するためには、int のベクトルのベクトル (各内部ベクトルは同じ長さ) が必要であると想像してください。

マトリックス データが正しい形式であることを検証する assert-matrix 関数を提供できます。

(defn assert-matrix [matrix] (...) )

ただし、flip 関数 (たとえば) には、関数に渡されたデータが検証されているかどうかを知る方法がありません (関数に渡す前にデータを検証する必要があるかどうかは、完全にユーザー次第です)。したがって、正確性を保証するには、flip を次のように定義する必要があります。

(defn flip [matrix]
    (assert-matrix matrix)
    (...))

ここには 2 つの主な問題があります。

  • マトリックス関数が呼び出されるたびに assert-matrix を呼び出し続ける必要があるのは非効率的です。
  • マトリックス関数を作成するときはいつでも、assert-matrix を呼び出すことを覚えておく必要があります。これを繰り返すのは退屈なので、忘れてしまう可能性があります。

オブジェクト指向言語では、インスタンスの作成時にコンストラクター引数の有効性をチェックするコンストラクターを使用して、Matrix という名前のクラスを作成します。クラスが初期化されたときにデータが検証されたことを確信できるため、メソッドが有効性を再チェックする必要はありません。

これは Clojure でどのように達成されるでしょうか?

4

2 に答える 2

2

プロトコルを使用してマトリックスのすべての操作を表し、マトリックスの「コンストラクター」のように機能する関数を作成できます。

(defprotocol IMatrix                                                                                                                                 
  (m-flip [_])                                                                                                                                       
  (m-rotate [_])                                                                                                                                     
  (m-vals [_]))                                                                                                                                      

(defn create-matrix [& rows]                                                                                                                         
  (if (apply distinct? (map count rows))                                                                                                             
    (throw (Exception. "Voila, what are you doing man"))                                                                                             
    (reify                                                                                                                                           
      IMatrix                                                                                                                                        
      (m-flip [_] (create-matrix rows))                                                                                                              
      (m-rotate [_] (create-matrix rows))                                                                                                            
      (m-vals [_] (vec rows))))) 



(def m (create-matrix [1 2 3] [4 5 6]))                                                                                                              
(m-flip m)
于 2013-02-04T16:03:55.603 に答える
2

データ構造を 1 回だけ検証する方法はいくつかあります。たとえばwith-matrix、次の行に沿ってマクロを記述できます。

(defmacro -m> [matrix & forms]
  `(do
    (assert-matrix ~matrix
      (-> ~matrix
        ~@forms))

これにより、次のことが可能になります。

(-m> matrix flip rotate)

上記は、スレッド化マクロを拡張して、ユースケースにうまく対処できるようにします。

同じアプローチには無限のバリエーションが存在する可能性がありますが、考え方は同じである必要があります。マクロは、検証コードが埋め込まれていないマトリックスで動作する関数を使用して、検証が成功した場合にのみコードの一部が実行されるようにします。メソッドの実行ごとに 1 回ではなく、コード ブロックごとに 1 回検証が実行されます。

もう 1 つの方法は、行列関数へのすべてのコード パスのどこかに検証境界があることを確認することです。

もご覧くださいtrammel

于 2013-02-04T13:25:24.983 に答える