関数型言語は、定義上、状態変数を維持するべきではありません。では、なぜHaskellやClojureなどがソフトウェアトランザクションメモリ(STM)実装を提供するのでしょうか。 2つのアプローチの間に矛盾はありますか?
可変状態を維持する関数型言語に問題はありません。 Haskellなどの「純粋な」関数型言語でさえ、現実の世界と対話するために状態を維持する必要があります。 Clojureのような「不純な」関数型言語は、状態の変化を含む可能性のある副作用を許容します。
重要な点は、関数型言語は、本当に必要な場合を除いて、可変状態を阻止することです。一般的なスタイルは、純粋な関数と不変データを使用してプログラミングし、それを必要とするコードの特定の部分で「不純な」可変状態のみと対話することです。そうすれば、コードベースの残りの部分を「純粋」に保つことができます。
STMが関数型言語でより一般的である理由はいくつかあると思います。
私は個人的には可変性を許可するClojureのアプローチが好きですが、STMトランザクションに参加する可能性がある厳密に制御された「管理された参照」のコンテキストでのみです。言語の他のすべては「純粋に機能的」です。
;; define two accounts as managed references
(def account-a (ref 100))
(def account-b (ref 100))
;; define a transactional "transfer" function
(defn transfer [ref-1 ref-2 amount]
(dosync
(if (>= @ref-1 amount)
(do
(alter ref-1 - amount)
(alter ref-2 + amount))
(throw (Error. "Insufficient balance!")))))
;; make a stranfer
(transfer account-a account-b 75)
;; inspect the accounts
@account-a
=> 25
@account-b
=> 175
上記のコードは完全にトランザクション的でアトミックです。別のトランザクション内の2つのバランスを読み取る外部オブザーバーは常に一貫したアトミック状態を参照します。つまり、2つのバランスの合計は常に200になります。ロックベースの同時実行では、これは驚くほど難しい問題です。多くのトランザクションエンティティを持つ大規模で複雑なシステムで解決する。
いくつかの追加の啓蒙のために、リッチヒッキーは このビデオでClojureのSTMを説明する優れた仕事 を行います
関数型言語は、定義により、状態変数を維持すべきではありません
あなたの定義は間違っています。状態を維持できない言語は使用できません。
関数型言語と命令型言語の違いは、一方が状態を持ち、もう一方が状態を持たないことではありません。それは彼らが状態を維持する方法にあります。
命令型言語は、プログラム全体に州が広がっています。
関数型言語は、型シグネチャによって明示的に状態を分離し、維持します。そしてそれが、STMのような高度な状態管理メカニズムを提供する理由です。