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

関数型プログラミングへの移行は、約10年前に本格的に始まりました。 Scala、Clojure、F#などの言語がどのように注目を集め始めたかを見ました。 この動きは、「おお、かっこいい、新しい言語!」という通常の称賛以上のものでした。 この動きを本当に促す何かがありました-または私たちはそう思いました。







ムーアの法則によれば、コンピューターの速度は18か月ごとに2倍になります。 この法律は1960年代から2000年代まで尊重されていました。 そして、それは止まりました。 憂鬱に。 周波数は3 GHzに達し、安定しました。 光の速度の制限が達成されました。 信号は、高速を提供するのに十分な速度でチップの表面を伝播できませんでした。







したがって、機器開発者は戦略を変更しました。 より大きな帯域幅を達成するために、彼らはより多くのプロセッサ(コア)を追加しました。 これらのコアのスペースを確保するために、チップからほとんどのキャッシングおよびパイプライン機器を削除しました。 したがって、プロセッサは以前よりも少し遅くなりましたが、もっと多くありました。 スループットが増加しました。







8年前に初めてデュアルコアマシンを手に入れました。 2年後、クアッドコア車を購入しました。 それで、核の再生が始まった。 そして、これは想像もしなかった方法でソフトウェア開発に影響を与えることを皆が理解していました。







私たちの反応の1つは、関数型プログラミング(FP)の研究でした。 FPは、一度初期化された変数の状態の変化を強力に防ぎます。 これは並行性に大きな影響を及ぼします。 変数の状態を変更できない場合、競合状態にはなりません。 変数の値を更新できない場合、並列更新の問題は発生しません。







もちろん、これはマルチコア問題の解決策と考えられていました。 コアの数が増えると、並行性は失われ、 同期が重要な問題になります。 FPは、1つのプロセッサで1024コアで動作する問題を軽減するプログラミングスタイルを提供することになっています。







だから、誰もがClojure、またはScala、またはF#、またはHaskellの研究を始めました。彼らは商品が彼らのところに来ていることを知っていて、到着したときに準備したかったからです。







しかし、商品は届きませんでした。 6年後、クアッドコアのラップトップを購入しました。 それ以来、私にはさらに2つありました。 私が購入する次のラップトップもクワッドになるようです。 さらなる安定化を観察していますか?







ところで、昨夜、2007年の映画を見ました。 ヒロインはラップトップを使用し、流行のブラウザでページを閲覧し、グーグルを使用し、クラムシェル電話でテキストメッセージを受信しました。 ああ、それは時代遅れでした-私はラップトップが古いモデルであり、ブラウザが古いバージョンであり、電話が現代のスマートフォンから遠く離れていることがわかりました。 しかし、これらは2000年から2011年までの変化ほど印象的な変化ではありませんでした。また、1990年から2000年までの変化ほど印象的ではありませんでした。

まあ、おそらくAFはかつて考えていたほど重要なスキルではありません。 たぶん私たちはコアの下に埋もれないでしょう。 32768コアのチップについて心配する必要はないでしょう。 リラックスして変数の更新に戻ることができるかもしれません。







それは間違いだと思います。 素晴らしいもの。 これはgoto



た使用と同じくらい大きな間違いだと思います。 動的ディスパッチを拒否するのと同じくらい危険だと思います。







なんで? 最初に興味がある理由から始めることができます。 FPは並行性をより安全にします。 多数のスレッドまたはプロセスを持つシステムを作成する場合、FPを使用すると、競合状態や発生する可能性のある並列更新に関する問題の数が大幅に削減されます。







なぜ他に? まあ、FPは書きやすく、読みやすく、テストしやすく、理解しやすいです。 あなたの何人かが腕を振って画面で叫んでいるのを想像してください。 FPを試してみて、好きなものを見つけましたが、簡単ではありませんでした。 これらはすべてmapとreduceであり、この再帰(特に末尾の再帰)は単純なものではありません。 もちろん。 わかった。 しかし、これは単なるデートの問題です。 これらの概念に精通すると、そしてこの知人の開発にそれほど時間はかからないので、プログラミングはずっと簡単になります。







なぜ簡単になるのですか? システムのステータスを監視する必要がないためです。 変数の状態は変更できないため、システムの状態は変更されません。 また、システムだけでなく追跡する必要もありません。 これらのデータ構造は変更できないため、リスト、セット、スタック、キューのステータスを監視する必要はありません。 FP言語でスタックの一番上にアイテムを配置すると、古いスタックを変更するのではなく、新しいスタックを作成します。 これは、プログラマーが空中で同時にボールをジャグリングする必要が少ないことを意味します。 記憶に残る。 あまり追跡されません。 これにより、コードの記述、読み取り、理解、およびテストが容易になります。







では、どのFP言語を使用する必要がありますか? 私のお気に入りはClojureです。 このClojureがとてつもなくシンプルな理由は、美しくシンプルな言語であるLispの方言だからです。 見せてあげましょう。







これはJavaの関数です: f(x)



;

さて、それをLisp上の関数に変えるには、最初のブラケットを左に移動するだけです: (fx)









これで、95%Lispを知っており、99%Clojureを知っています。 括弧付きの少し愚かな構文は、実際にはこれらの言語の構文に関するほとんどすべてです。 それらはばかばかしいほど単純です。







おそらく、あなたは以前にLispプログラムを見ていて、これらすべての括弧が気に入らなかったかもしれません。 そして、多分あなたはCAR



CDR



CADR



などが好きではありませんでした 心配しないで。 ClojureはLispよりも句読点が少し多いので、括弧は少なくなります。 また、Clojure CAR



では、 CDR



CADR



first



rest



second



置き換えられます。 さらに、ClojureはJVMに基づいており、Javaライブラリ全体、および必要なその他のJavaフレームワークまたはライブラリへのフルアクセスを提供します。 互換性は迅速かつ簡単です。 さらに良いことに、ClojureはJVMのオブジェクト指向機能への完全なアクセスを提供します。







「ちょっと待って!」、「FPとOOPは相互に互換性がありません!」と言うのを聞きました。 誰が言った? これはナンセンスです! ああ、FPではオブジェクトの状態を変更できないのは事実ですが、それではどうでしょうか。 スタックに番号を追加すると新しいスタックが得られるように、メソッドオブジェクトの設定値を呼び出すと、古いオブジェクトを変更する代わりに新しいオブジェクトが得られます。 これは、慣れるとすぐに非常に簡単に処理できます。







しかし、OOPに戻ります。 ソフトウェアアーキテクチャレベルで最も役立つと思うOOPの機能の1つは、動的なポリモーフィズムです。 また、ClojureはJavaの動的なポリモーフィズムへのフルアクセスを提供します。 おそらく例でこれをよりよく説明するでしょう。







 (defprotocol Gateway (get-internal-episodes [this]) (get-public-episodes [this]))
      
      





上記のコードは、JVMのポリモーフィックインターフェイスを定義しています。 Javaでは、このインターフェースは次のようになります。







 public interface Gateway { List<Episode> getInternalEpisodes(); List<Episode> getPublicEpisodes(); }
      
      





JVMレベルでは、生成されるバイトコードは同一になります。 実際、Javaで書かれたプログラムは、Javaで書かれていればインターフェースを実装します。 同様に、ClojureプログラムはJavaインターフェースを実装できます。 Clojureでは、次のようになります。







 (deftype Gateway-imp [db] Gateway (get-internal-episodes [this] (internal-episodes db)) (get-public-episodes [this] (public-episodes db)))
      
      





db



コンストラクターパラメーターと、これらすべてのメソッドがどのようにアクセスできるかに注意してください。 この場合、インターフェイスの実装は、単にdb



を転送するいくつかのローカル関数に委任されます。







おそらく最良ののは、Lisp、したがってClojureが(待機、待機) ホモ円錐であるという事実です。つまり、コードはプログラムが操作できるデータであるということです。 見やすいです。 次のコード(1 2 3)



は、3つの整数のリストを表します。 (f 2 3)



ように、最初の要素が関数であることが判明した場合、これは関数呼び出しになります。 したがって、Clojureのすべての関数呼び出しはリストであり、リストはコードから操作できます。 したがって、プログラムは他のプログラムを作成して実行できます。







ポイントはこれです。 関数型プログラミングは重要です。 勉強する必要があります。 また、どの言語を学ぶべきか心配な場合は、Clojureをお勧めします。








All Articles