定義上、関数型言語は状態変数を保持すべきではありません。では、なぜHaskellやClojureなどがソフトウェアトランザクションメモリ(STM)の実装を提供しているのでしょうか?2つのアプローチの間に矛盾はありますか?
定義上、関数型言語は状態変数を保持すべきではありません。では、なぜ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つのバランスを読み取る外部オブザーバーは、常に一貫したアトミック状態を確認します。多くのトランザクションエンティティを持つ大規模で複雑なシステムで解決するため。
さらなる啓発のために、Rich HickeyはこのビデオでClojureのSTMを説明する素晴らしい仕事をしています
定義上、関数型言語は状態変数を維持すべきではありません
定義が間違っています。状態を維持できない言語は使用できません。
関数型言語と命令型言語の違いは、一方の言語には状態があり、もう一方の言語にはないということではありません。それは彼らが状態を維持する方法です。
命令型言語の状態はプログラム全体に広がっています。
関数型言語は、型シグネチャを介して明示的に状態を分離および維持します。そして、それが彼らがSTMのような洗練された状態管理メカニズムを提供する理由です。
プログラムには可変状態(たとえば、Webアプリのデータベースコンテンツ)が必要な場合があり、関数型プログラミングの利点を失うことなくそれを使用できると便利です。非機能言語では、可変状態がすべてに浸透します。何らかの特別なAPIを使用して明示的にすると、他のすべてが純粋に機能している間に、識別可能な小さな領域に限定できます。FPの利点には、簡単なデバッグ、反復可能なユニットテスト、痛みのない同時実行性、およびマルチコア/ GPUの使いやすさが含まれます。