2

これは私の以前の質問のフォローアップです。

Let Over Lambdaを読んで奇妙なオブジェクトスキームを思いついたので、プロトコルに勝る利点は考えられませんが、意見を聞きたいと思います。高階関数とカプセル化の使用を検討しているところです。

(defn new-person
  "Construct a new Person object and return a Map of accessor methods."
  [init-first-name init-last-name init-age]
  (let [first-name (ref init-first-name)
        last-name (ref init-last-name)
        age (ref init-age)]
    {:get-first-name #(@first-name)
     :set-first-name #(dosync (ref-set first-name %1))
     :get-last-name #(@last-name)
     :set-last-name #(dosync (ref-set last-name %1))
     :get-age #(@age)
     :set-age #(dosync (ref-set age %1))}))

次のようなオブジェクトを使用できます。

(def fred (new-person "fred" "flintstone" 42))

次の方法でアクセサメソッドを取得します。

(fred :get-age)

しかし、アクセサーを呼び出す方法がわかりません。

「インスタンス」変数のすべての変更はSTMで発生するため、作成されたオブジェクトはスレッドセーフです。

更新:新しく改良されたバージョン:

(defn new-person
  "Construct a new Person object and return a Map of accessor methods."
  [init-first-name init-last-name init-age]
  (let [first-name (ref init-first-name)
        last-name (ref init-last-name)
        age (ref init-age)]
    {:first-name 
        (fn
          ([] @first-name)
          ([val] (dosync (ref-set first-name val))))
     :last-name
        (fn
          ([] @last-name)
          ([val] (dosync (ref-set last-name val))))
     :age
        (fn
          ([] @age)
          ([val] (dosync (ref-set age val))))}))
4

3 に答える 3

5

あなたの質問に対する100%の答えではないかもしれませんが、Clojureにとってあまり慣用的ではありません。「標準」ソリューションは次のようになります。

(defrecord Person [first-name last-name age])
(def fred (Person. "fred" "flintstone" 42))
(fred :age)

OOの可変状態をClojureの「オブジェクト」に強制しているようです

于 2011-05-15T14:19:09.993 に答える
3

フォローアップの質問と同じですが、フォームを別の括弧で囲みます。内部フォームが関数を返す場合、それは関数を返すシンボルと同じです。ルールは、括弧内の最初のフォームが常に特殊なフォーム、マクロ、または関数として検索されることです。この動作を防ぐには、引用符のようなものが必要です。

user=> (fred :get-age)
#<user$new_person$fn__531 user$new_person$fn__531@c4afc4>
user=> ((fred :get-age))
42

それはと同じです

user=> (let [age-getter (fred :get-age)] (age-getter))
42
于 2011-05-15T18:40:45.050 に答える
1

Clojureの哲学は、レコードフィールド自体へのアクセスをカプセル化することではありません。カプセル化は、たとえばそのレコードで機能する一連の関数など、より高いレベルで行う必要があります。Clojureを参照してください-データ型:

情報のカプセル化は愚かなフィールドであり、依存関係を回避するためにプロトコル/インターフェースを使用します

于 2011-05-15T16:12:08.953 に答える