4

変更可能な状態がなく、すべての操作が世界の新しい状態を返す FP では。与えられた: 連絡先リストと個々の連絡先があります。

アドレス帳に Dirk を追加します。Dirk は私のアドレス帳の子です。私のアドレス帳は Dirk の親です。両方の参照を同時に設定できないので、ジレンマがあります。親子関係は、親から子へ、親から同じ子へ永遠にステップできる無限のサイクルを定義する必要があります。

JavaScript 構文の使用:

var addresses = new AddressBook();
var dirk = new Contact(addresses, 'Dirk', ...);

2 行目では、Dirk なしでアドレス帳を渡しています。Dirk には、彼のいないアドレス帳への親参照があります。

私は答えを疑っているが、私は確信したい。これを適切に設定するために実際に状態を変更するつもりですか、それとも見落としているテクニックがありますか?

4

3 に答える 3

3

この種のものを JavaScript の例のように動作させたい場合 (つまり、実際の子で実際のアドレス帳を直接検索できるようにする場合)、アドレス帳を変更可能にする必要があります。親と子が最初に作成されたからでもありません (一部の関数型言語では、他の言語よりも簡単に管理できます)。その後、アドレス帳への参照をさらに追加すると、古いエントリが削除されます。古いバージョンのアドレス帳をまだ保持しています。

Clojure では、このような場合にアドレス帳全体を保持するために Atom または Ref を使用してから、各子のアドレス帳を指す Atom または Ref を配置したくなるかもしれませんが、Clojure の参照型は実際には不変データを保持するように設計されているだけです。それらをネストすると問題が発生する可能性があります。

より良い解決策は、エンティティに記号名 (キーワード、数字、UUID はすべて問題ありません) を付けて、マップのどこかに保存することです。単一のアトムを使用すると、次のようになります。

(def state (atom {:contacts {:dirk ...}
                  :address-books {}}))

次に、次のように Dirk を新しいアドレス帳に追加できます (途中でハッシュ マップの形式で作成します)。

(swap! state (fn [state-map]
               (update-in state-map [:address-book :my-address-book]
                 (fn [abook]
                   (let [entries (get abook :entries [])]
                     (assoc abook :entries (conj entries :dirk)))))))

これにより、Dirk がシンボリック参照 ( ) の形式でアドレス帳に追加され、キー:dirkの下のトップレベルの状態マップで検索されることに注意してください。:contactsDirk の連絡先に、それがメンバーであるアドレス帳のリストを維持することも必要な場合はupdate-in、適切な情報を Dirk の連絡先に追加して、次のようにネストを削除することもでき->ます。

(-> state-map
    (update-in [...] ...)
    (update-in [...] ...))
于 2013-07-13T01:15:02.207 に答える
2

一般的にFPについて言及したので、もう1つのビューを追加します-遅延評価。私は JS も Clojure も苦手なので、別の言語で例を挙げますが、そのアイデアも使えるかもしれません。

多くの関数型言語には、遅延評価の概念があります。これは、値が実際に必要な時点でのみ計算されることを意味します。当然のことながら、このような遅延計算は参照透過的でなければなりません (外部情報に依存してはならず、変更可能な状態や副作用などから解放されていなければなりません)。これは、それらがいつ評価されるか (またはまったく評価されるか) が分からないためです。

たとえば、Haskell ではすべての計算が遅延なので、次のように書くことができます。

let address = Address contact {- other fields -}
    contact = Contact address {- other fields -}
 in {- some expression that uses address and contact -}

または、テールがリスト自体であるリストを作成することもできます。結果は、一定量のメモリしか必要としない要素が繰り返される無限リストです。

infList :: a -> [a]
infList x = l
  where l = x : l

詳細については、Haskell Wikiの結び目を結ぶを参照してください。

言語に遅延評価がない場合は、自分で実装できます。値がまだ要求されていない場合は、計算して保存し、返します。次回は、以前に計算されたものを返すだけです。もちろんそれには可変性が必要ですが、可変状態はソフトウェアコンポーネントの内部に隠されているため、計算が参照透過的であれば、可変性が漏れることはありません。

于 2013-07-13T14:28:32.950 に答える