0

というプロトコルがあり、それを実装IExampleするレコード タイプを定義します。A

(defprotocol IExample
  (foo [this] "do something")
  (bar [this] "do something else"))

(defrecord A [field1 field2]
  IExample
  (foo [this]
    (+ field1 field2))
  (bar [this]
    (- field1 field2)))

Bこのプロトコルを実装するために別の (基本的な) 型を拡張したいが、 から に変換する方法を知っているとしましょBA:

 (defn B-to-A
   "converts a B object to an A object"
   [Bobj] ...)

この変換があるため、上のプロトコルのすべての呼び出しを委任することで、IExampleBIExampleプロトコルにA委任できます。

(extend B
  IExample {
    :foo (fn [this] (foo (B-to-A this)))
    :bar (fn [this] (bar (B-to-A this)))})

ただし、これは非常に多くのボイラープレート (特に大きなプロトコルの場合) であり、clojure の慣用句ではないようです。

関数を使用して、オブジェクトで関数が呼び出されるたびに暗黙的に変換Bするようにclojureに指示するにはどうすればよいですか?AIExampleBB-to-A

4

2 に答える 2

2

ボイラープレートに関する限り、ボイラープレートをすべて作成するマクロを作成できます。一方、ここでデザインをもう一度見ることができます。

ここにあるのはA、 、Bおよびの 3 つのもの (タイプ) ですIExample。そして、これらの間には 2 つの関係がa-to-example : A -> IExampleありb-to-a : B -> Aますcompose b-to-a with a-to-example : B -> IExample。この設計をプロトコルに移行しようとすると、上記の設計で説明したようにプロトコルが直接構成されないため、単純な変換ではないことがわかります。代わりに、IToExample以下に示すような中間プロトコルを使用できます。

(defprotocol IExample
  (foo [this] "do something")
  (bar [this] "do something else"))

(defprotocol IToExample
  (to-example [this] "convert to IExample"))

(defrecord A [field1 field2]
  IExample
  (foo [this]
    (+ field1 field2))
  (bar [this]
    (- field1 field2))
  IToExample
  (to-example [this] this))

(deftype B [])
(defn b-to-a [b] (A. ....))
(extend B
  IToExample {:to-example b-to-a})

私たちが行ったことは-> IExample、私たちの設計IToExampleで を 1 つの機能を持つプロトコルとして表したものです。したがって、次のようになりました。

  • a-to-example : A -> IExampleA に IToExample を実装することにより
  • b-to-a : B -> A通常の関数で
  • compose b-to-a with a-to-example : B -> IExampleB に IToExample を実装し、b-to-a を使用します。
于 2013-10-28T16:03:54.260 に答える