関数型プログラミングがソフトウェア開発の未来になるべき理由
(spectrum.ieee.org)- 「関数型プログラミング(FP)は学ぶのが難しいが、あなたのコードが不快な驚きを生みにくくしてくれる」
- FPでは「less is more」
- (Maybe/Option によって)Null Reference 問題を解決
- FPは学習曲線が急である
- FPの未来
- 少ない人数の開発者でより多くの開発を行うには、使えるあらゆるツールを活用すべきであり、FPはそのための切符である
- 私たちのような華やかではない会社は開発者の採用が難しい。しかし、FPのコードベースで働きたがるトップティアの開発者を採用できるようになる
- FPを採用すれば品質と堅牢性が向上し、FPでは発生しないバグに費やす時間が減るだろう
- FPの機能が主流言語で徐々に見られるようになっているのは、ソフトウェア業界がパラダイムシフトの準備をしていることを示している
- 業界が完全に移行するまでには多くの作業が必要だろうが、このやり方の利点は明らかであるため、どこへ向かうのかについて疑う余地はない
13件のコメント
学習曲線が高いのは確かだと思います。コメントにも、本当の意味で関数型プログラミングをまったく理解していない内容がありますね。もちろん、よく分かったうえで書かれたコメントもあります。関数型は難しいです。私もまだ勉強中です……
プログラミング言語がもはや開発チームの好みではなく、会社の生き残りの問題になるケースが生まれて初めて、私たちはFPの必要性についてもう一度語ることができるのでしょう。
私が整理します。メモリ管理と一部のアルゴリズムでは、まだオブジェクト指向を上回れていません。状況とコストに応じて適切に使えばよいです。
うーん……学習曲線が急だという主張には同意できません。
まず単純に簡単で、ミスの余地が減り、その結果として生産性が高まります。
それで十分でしょう。
人間の思考や業務を、純粋関数型プログラミング言語のように完璧に定式化するのは難しいですよね。free monad みたいなのを見ると、結局
rxjsくらいまでが最大許容範囲なのかなと。FPも本末転倒になる瞬間が来ます。
既存のFPの効果も、データとメソッドを分離した程度ですし、
Optionalが思ったより使われていないのを見ても、型抽象は不要な抽象化だと思います(型を合わせるために生産性をかなり削ってしまう)。
クロージャのようにデータと演算をさらに抽象化する方向でない限り、既存言語を活用するには限界があります。
不変性は、関数型プログラミングのパラダイムでよく使われる道具の一つにすぎません。
私の知る限り、関数型プログラミングのパラダイムとは、「副作用」(Side effect) をできるだけ制御しようとするプログラミングパラダイムです。
副作用を制御しようとすると、自然と参照透過性や不変性、純粋関数といったものを重視するようになるのだと理解しています。
そういう意味では、あえて関数型プログラミング言語を使わなくても、自分が書く関数やメソッドの副作用を明確に認識し、それを適切に制御できるようにすることが望ましいと思います。これはコードの悪臭(Code smell)を減らし、単体テストも書きやすくなるなど、利点が多いです。
これについてもう少し詳しく説明した翻訳記事もあります。
このような観点から、副作用を最小化するリファクタリングに焦点を当てた書籍としては、頭にスッと入る関数型コーディング: シンプルなコードで複雑なソフトウェアを手なずける があります。理論よりも実用的かつ実務的な観点からアプローチしているため、良いコードを書きたい人であれば、十分に読んで身につける価値があります。これを読んだあと、コードを書くときに副作用について以前よりずっと意識するようになるだけでも、本代の元は十分に取れる本だと思います。
ありがとうございます。探して読んでみます。
あ!翻訳書が出ていたんですね!読んでみます!
本のおすすめありがとうございます!! さっそく買って読んでみます!
あの本、本当に良かったです!
リファクタリングの観点から見ると、本当に使いやすいです
もちろん、関数型プログラミングも良い方法だとは思いますが、その長所を説得力をもって伝えてくれる人はあまりいない気がします。単に良いと言われても、なかなか実感が湧きませんよね?
以下は個人的な意見ですが、そして現代のあらゆるプログラムは事実上チューリングマシンを基盤に成り立っているので、抽象的には大きく関数とデータに分けられるはずで、そのため手続き型プログラミングも根源的には関数型だと考えています。では、関数型の手続き型に対する本当の利点は何かと言えば、単に「グローバル、あるいはそれに準ずるスコープの変数を使わないこと」だと思います。この利点によって、「関数と関数の間の分離」や「マルチスレッドコンピューティング」にも効率的です。
しかし、これは関数型プログラミングでしか得られない利点かと言えば、そうではありません。手続き型言語でも dependency injection の概念を通じてクラスおよび関数単位での分離が推奨されていますし(すでにモダンなフレームワークはどれも基本的に採用しています)、Rust 言語では言語レベルの制約によって扱いやすい並行コンピューティングを目指せるようになっています。
要するに、関数型言語は良い言語であり方法論でもありますが、「進化的な意味で優れている」というよりは、Go や Rust のように「失敗する可能性を言語レベルで排除しようと努めている一方で、使いこなすのが難しい言語」だと思います。
手続き型言語でも関数合成のようなことが可能だという意味でしょうか?
「関数合成」の定義を狭く捉えると、関数型言語でしかできないと考えるかもしれませんが、よく考えてみればその実行も結局は手続き型言語である機械語やアセンブリ言語の上で動いています。つまり、これは「可能か不可能か」の問題ではなく、「言語の関心事、好み、哲学」の問題です。「関数合成」の定義を狭く「特定の言語の特定の機能」としてではなく、「論理的な機能同士の合成」として広く捉えれば、いくらでも可能です。そして、関数型言語の利点が確かに存在するからこそ、それを積極的に取り入れたものが
rxjsやsparkなどです。みなさんが情報系で学んだとおり、以下は同じ結果ですが、ただ表現形式が違うだけです。そして前置は関数型と呼ばれることが多いですね。
前置記法 : + 1 1
中置記法 : 1 + 1
後置記法 : 1 1 +