実用的な関数式プログラミング

4382 ワード

関数式プログラミング(functional programming)が本格的に発展し始めたのは10年前で、その時からScala、Clojure、F#という言語が注目され始めた.このような関心は「わあ、新しい言語、かっこいい!」だけではありません.このような短い熱は、確かにいくつかの実際の原因がそれを推進している--あるいは少なくとも私たちはそう思っています.
ムーアの法則は私たちに18ヶ月ごとにコンピュータの速度が2倍になることを教えてくれた.この法則は1960と2000からずっと有効だ.しかしその後、それは失効し始め、徐々に冷却された.クロック周波数が3 ghzに達した後、ボトルネック期に達した.光の速度の制限に達しました信号はチップ表面でより高い速度で急速に伝搬できない.
ハードウェア設計者はポリシーを変更しましたより大きなスループットを得るために、より多くのプロセッサ(コア数)を追加する.同時に、これらのコアのために空間を空けるために、チップから多くのキャッシュ(cacheing)とパイプ(pipelining)ハードウェアを除去した.従って、プロセッサは確かに以前より少し遅いが、より多くのプロセッサがあるため、スループットは依然として増加する.
8年前、私は最初のデュアルコアマシンを持っていました.2年後、私は4核の機械を持っていました.これらのコア数はすでに増加し始めている.その時、私たちは想像できない方法でソフトウェアの発展に影響を与えると信じていました.
そこで、関数式プログラミング(FP)の勉強を始めました.変数が初期化すると、関数式プログラミングは変数の状態を変更することを強くサポートしない.これは同時(concurrency)に深い影響を及ぼしている.変数の状態を変えることができなければ、競争条件はありません.変数の値を更新しても、同時に更新する問題はありません.
もちろん、これは多核問題の解決策とされていた.コア数が急増すると、同時に、止まらない!同時性(simultaneity)は非常に顕著な問題になるだろう.関数式プログラミングは、単一のプロセッサで1024コアに対応する可能性のある問題を軽減するプログラミング方式を提供するべきである.
だから、すべての人はClojure、Scala、F#またはHaskellを勉強し始めました.彼らは関数式のプログラミングが最終的に異彩を放つと信じているので、この日のために事前に準備したいと思っています.
しかし、この日は結局来なかった.6年前に4コアのノートを持って、それから私はまた2つの4コアを持っていました.私の次のノートも4コアだと思います.私たちはまた別のボトルネック期になりましたか?
余談ですが、昨夜2007年の映画を見ました.ヒロインはノートパソコンを使って、Googleを使っておしゃれなブラウザでホームページを閲覧し、カバーをめくって携帯電話で情報を受信しています.すべてはそんなに熟知している.しかし、これはもう時代遅れです.ノートパソコンのモデルが古く、ブラウザは古いバージョンで、携帯電話を覆うのは今日のスマートフォンとは本当に遠いことがわかります.しかし--この変化は2000年から2011年のように劇的ではなく、1990年から2000年の天地を覆すこともない.私たちはまたコンピュータとソフトウェア技術のボトルネックになりましたか?
だから、関数式のプログラミングは私たちが想像していたほど重要ではないかもしれません.私たちはそんなに多くのコアに囲まれないかもしれませんが、チップに32768のコアがあることを心配する必要はありません.リラックスして、前に変数を更新したときに戻ることができるかもしれません.
しかし、gotoの乱用と同じように深刻な誤りになると思います.ダイナミックスケジューリング(dynamic dispatch)を放棄するのと同じように危険です.
どうしてですか.最初に興味のあるところから始めましょう.関数式のプログラミングは同時化を容易にします.多くのスレッドやプロセスを持つシステムを構築する場合は、関数プログラミングを使用すると、競争条件や同時更新による問題を大幅に減らすことができます.
まだありますか?関数式プログラミングは書きやすく、読みやすく、テストと理解しやすい.それを聞いて、多くの人が興奮し始めたと信じています.関数式のプログラミングを試してみると、すべてが簡単であることがわかります.すべてのmap、reduceと再帰--特に末尾再帰は、非常に簡単です.これらを使用するのは熟知度の問題にすぎない.これらの概念に慣れると、あまり時間がかからず、プログラミングが容易になります.
どうして簡単になったの?システムの状態を追跡する必要がないからです変数の状態は変えられないため、システムの状態も変わらない.追跡を必要としないのは、システム、リスト、集合、スタック、キューなどのパスだけでなく、これらのデータ構造も変更できないため、追跡を必要としない.関数式プログラミング言語では、スタックpush要素に新しいスタックが得られ、元のスタックは変更されません.これはプログラマーの負担を軽減することを意味し、彼らが記憶する必要があるものはもっと少なく、追跡する必要があるものはもっと少ない.したがって、コードは書きやすく、読みやすく、理解しやすく、テストしやすい.
では、どの関数式プログラミング言語を使うべきですか.私が一番好きなのはClojureです.Clojureは極めて簡単だからだ.それはLispの方言で、Lispはとても簡単できれいな言語です.ここで、少し展示します.
Javaの関数:f(x);
ここで、Lispの関数に変換する、最初の括弧を簡単に左に移動すればよい:(f x).
今、あなたはすでに95%のLispと90%のClojureをマスターしました.これらの言語にとって、これらの括弧はすべての文法です.極めて簡単である.
Lispプログラムを見たことがあるかもしれませんが、カッコは好きではありません.CAR、CDR、CADRも好きではないかもしれません.心配しないで.ClojureはLispよりも多くの記号を持っているので、括弧は比較的少ない.ClojureはCAR,CDR,CADRの代わりにfirst,rest,secondを用いた.また、ClojureはJVMに基づいて、Javaライブラリ、その他のJavaフレームワークとライブラリに完全にアクセスできます.その相互運用性は迅速で便利である.より良い点は、ClojureがJVMの完全なオブジェクト指向の特徴を持つことができることである.
「ちょっと待って!」「関数プログラミングとオブジェクトに直面するのは互いに互換性がありません!」と言うかもしれません.誰が言ったの?事実はそうではない!関数式のプログラミングでは、オブジェクトの状態を変えることはできません.でもそれはどうですか?オブジェクトを変更したい場合は、新しいオブジェクトを取得すればいいです.前のオブジェクトは変更する必要はありません.これに慣れると、これは非常に扱いやすいです.
オブジェクトに戻る.オブジェクト向けに最も有用な特性の一つは、ソフトウェアアーキテクチャの面での動的多態性であることを発見した.ClojureはJavaの動的多態性に対する完全なアクセスを提供した.例で説明したほうがいいです.
(defprotocol Gateway
  (get-internal-episodes [this])
  (get-public-episodes [this]))

上のコードはJVMのマルチステートinterfaceを定義する.Javaでは、このインタフェースは次のように見えます.
public interface Gateway {
    List getInternalEpisodes();
    List getPublicEpisodes();
}

JVMというレベルでは、生成するバイトコードは全く同じである.実際、Clojureの書き込みプログラムがこのインタフェースを実現するのはJavaの実現のようなものです.Clojureプログラムは同じtokenでJavaのinterfaceを実現します.Clojureでは、このように見えます.
(deftype Gateway-imp [db]
  Gateway
  (get-internal-episodes [this]
    (internal-episodes db))

  (get-public-episodes [this]
    (public-episodes db)))

構造関数パラメータdbとすべての方法がどのようにアクセスするかに注意する.上記の例では、インタフェースの実装は、dbを渡すことによって、いくつかのローカル関数に簡単に委任されるだけである.
Lispと同様、Clojureも同像性(Homoiconic)の言語である、つまり、コード自体がプログラムが操作できるデータである.これはわかりやすい.次のコード:(1 2 3)は、3つの整数のリスト(list)を表す.リストの最初の要素が関数、すなわち(f 2 3)になると、関数呼び出しになる.したがって、Clojureでは、すべての関数呼び出しがリストとなる.リストは直接コードで操作することができる.したがって、1つのプログラムは、他のプログラムを構築して実行することもできる.
最後に、関数式のプログラミングは非常に重要です.君はそれを学ぶべきだ.どの言語から学ぶべきかまだ考えているなら、Clojureをお勧めします.
Pragmatic Functional Programming