24

defrecordClojureで独自の不変データ型/メソッドを作成しようとしています。目標は、インスタンスを作成できるデータ型を用意し、そのメソッドを呼び出して、変更された変数を持つそれ自体の新しいコピーを返すことです。a と b がベクトルだとします。両方の値を更新し、それらのベクトルが更新された構造全体の新しいコピーを返したいと思います。これは明らかにコンパイルされません。私は自分の考えを伝えようとしているだけです。

(defrecord MyType [a b]
  (constructor [N]
    ; I'd like to build an initial instance, creating a and b as vectors of length N
  ) 

  (mutate-and-return [] 
    ; I'd like to mutate (assoc the vectors) and return the new structure, a and b modified
  )
)

コンストラクターを呼び出してから、ミューテーターを好きなだけ呼び出したいと思います(ミューテーションしない関数は他にもありますが、質問のためにこれ以上複雑にしたくありません)。

あるいは、これが慣用的な Clojure ではない場合、どのようにしてこのようなことを行うのでしょうか?

4

3 に答える 3

36

レコードを定義する方法は次のとおりです。

(defrecord MyType [a b])

Clojureでは、通常、レコードタイプ自体に「メソッド」を定義しないことに注意してください(例外は、Javaインターフェイスまたはプロトコルを直接実装する場合です)。

基本的なコンストラクター(接頭辞->)は無料で自動的に生成されます。

(def foo (->MyType [1 2 3] [4 5 6]))

foo
=> #user.MyType{:a [1 2 3], :b [4 5 6]}

次に、これを使用するより洗練されたコンストラクター関数を記述できます。

(defn mytype-with-length [n]
  (let [a (vec (range n))
        b (vec (range n))] 
    (->MyType a b)))

(mytype-with-length 3)
=> #user.MyType{:a [0 1 2], :b [0 1 2]}

また、「mutate-and-return」も無料で提供されます。assocを使用するだけです。

(assoc foo :b [7 8 9])
=> user.MyType{:a [1 2 3], :b [7 8 9]}
于 2012-08-14T18:21:16.027 に答える