関数型プログラミングがまだ引き継がれていないのはなぜですか?


197

私は宣言型/関数型プログラミング(言語)に関するテキストを読んだり、Haskellを試したり、自分で書いたりしました。私が見てきたことから、関数型プログラミングには、古典的な命令型スタイルに比べていくつかの利点があります。

  • ステートレスプログラム; 副作用なし
  • 並行性; 増加するマルチコアテクノロジーで非常に優れた再生
  • プログラムは通常短く、場合によっては読みやすくなります
  • 生産性が上がる(例:Erlang)

  • 命令型プログラミングは非常に古いパラダイムであり(私の知る限り)、21世紀にはおそらく適さない

なぜ企業が関数型言語で使用されているプログラムや関数型言語で書かれたプログラムがまだ「まれ」であるのですか?

関数型プログラミングの利点を検討するときに、依然として命令型プログラミング言語を使用しているのはなぜですか?

1990年には早すぎるかもしれませんが、今日はどうでしょうか。


1
注:この質問はmetaで少なくとも2回議論されており、コンセンサスは、上記の「歴史的重要性」ロックによってアーカイブされたとしても、保持する必要があるということです。ロックを解除することを目的としてこれをご覧になっている方は、この質問についてのもう1つの退屈なディスカッションに参加せず、そのまま答えを楽しんでビジネスに取り掛かる必要がないことを強くお勧めします。
Shog9 2016

回答:


530

これらの利点はすべて欠点でもあるからです。

ステートレスプログラム; 副作用なし

実社会のプログラムはすべて副作用と突然変異についてです。ユーザーがボタンを押すのは、何かを起こしたいからです。彼らが何かをタイプするとき、彼らはその状態が以前そこにあった状態を置き換えたいと思っています。会計のジェーン・スミスが結婚し、彼女の名前をジェーン・ジョーンズに変更するとき、彼女の給料を印刷するビジネスプロセスをサポートするデータベースは、その種の変異を処理することすべてに優れているべきです。エイリアンに機関銃を発射するとき、ほとんどの人はそれを、ヒットポイントの少ない新しいエイリアンの構築として精神的にモデル化しません。彼らはそれを既存のエイリアンの特性の突然変異としてモデル化します。

プログラミング言語の概念がモデル化されるドメインに対して根本的に機能する場合、その言語を使用することを正当化することは困難です。

並行性; 増加するマルチコアテクノロジーで非常に優れた再生

問題はただ押しのけられます。不変のデータ構造を使用すると、古いデータを処理する可能性を犠牲にして、スレッドの安全性が低下します。可変データ構造を使用すると、データの整合性を保つために複雑なロジックを記述する必要があるという犠牲を払って、常に新しいデータに取り組むという利点があります。これらのいずれかが明らかに他よりも優れているわけではありません。

プログラムは通常短く、場合によっては読みやすくなります

長くて読みにくい場合を除きます。関数形式で書かれたプログラムの読み方を学ぶことは難しいスキルです。人々は、プログラムを一連の計算を実行するよりも、レシピのように実行する一連のステップとして考える方がはるかに優れているようです。

生産性が上がる(例:Erlang)

機能的なスタイルでプログラミングする方法を知っているプログラマーを雇うことの莫大な費用を正当化するために、生産性は大幅に上昇しなければなりません。

また、稼働中のシステムを捨てたくはないことを覚えておいてください。ほとんどのプログラマーは、新しいシステムをゼロから構築するのではなく、既存のシステムを維持しています。そのほとんどは、非関数型言語で構築されています。それを株主に正当化することを想像してみてください。何百万ドルもの費用をかけて既存の給与計算システムを廃棄して新しいシステムを構築したのはなぜですか?「関数型プログラミングは素晴らしいので」と株主を喜ばせることはまずありません。

命令型プログラミングは非常に古いパラダイムであり(私の知る限り)、21世紀にはおそらく適さない

関数型プログラミングも非常に古いものです。コンセプトの時代がどのように関連しているかはわかりません。

誤解しないでください。私は関数型プログラミングが大好きです。関数型プログラミングの概念をC#に取り入れることを支援したかったので、このチームに参加しました。不変のスタイルでのプログラミングが未来の道だと思います。しかし、単純に望めない関数型のプログラミングには莫大なコストがかかります。より機能的なスタイルへの移行は、数十年の間にゆっくりと徐々に起こります。そして、それはそれが何であるかです:Haskellの純粋さと美しさの放棄とC ++の放棄を受け入れるのではなく、より機能的なスタイルへのシフト。

私は生活のためにコンパイラを構築しており、次世代のコンパイラツールの機能的なスタイルを確実に採用しています。これは、関数型プログラミングが基本的に私たちが直面しているこの種の問題に適しているためです。私たちの問題はすべて、生の情報(文字列とメタデータ)を取り込み、それらを異なる文字列とメタデータに変換することです。誰かがIDEで入力しているように、変更が発生する状況では、問題のスペースは本質的に、変更されたツリーの部分のみを増分的に再構築するなどの機能的手法に役立ちます。多くのドメインにはこれらの優れたプロパティがないため、機能的なスタイルに明らかに従うことができます


41
「会計のジェーン・スミスが結婚し、彼女の名前をジェーン・ジョーンズに変更するとき、彼女の給料を印刷するビジネスプロセスをバックアップするデータベースは、その種の変異を処理することについてすべてであった方がよいでしょう。」レコードはJane Smithの以前の名前になります。Janeの以前の名前のすべてのインスタンスを遡って彼女の新しい名前に更新しません;)
Juliet

40
@ジュリエット:確かに。私の要点は、従業員を表すオブジェクトがある場合、「従業員の名前を変更する」操作は、オブジェクトIDを変更しない従業員表すオブジェクトの変更であると考えるのが理にかなっているということです。ジェーン・スミスが彼女の名前を変更するとき、それ以外は同じであるジェーン・ジョーンズと呼ばれる別の従業員を作成しません。2つの異なる名前を持つ2人の従業員はいない。このプロセスは、新しいオブジェクトの構築としてではなく、オブジェクトの変異としてモデル化するのが自然です。
Eric Lippert、

24
これは良い答えですが、時々あなたのケースを誇張していると思います。ジュリエットが言ったように、人々はそれを名前の変更と考えるかもしれませんが、それは本当により深いレベルでの名前の置き換えです。また、関数型プログラムは(学習したスキルあるため)人々にとって読みにくいかもしれませんが、それは一般的に長いためではありません。Haskellプログラムは、ほとんどの場合、たとえば、Javaプログラムよりも簡潔です。多くの固有の状態を持つ「適合性の悪い」ドメインであってもです。
チャック

29
+1この答えを読むのはとても新鮮な空気でした。あなたの立場にいる誰かからそのような実用主義(関数型プログラミングへの根底にある情熱を伴う)を聞くのは素晴らしいです。
Dhaust

11
「これらすべての長所も短所なので、ステートレスプログラム。副作用はありません」:私が理解している限り(信頼できる回答を書くためにFPについて十分に知らない)、これは正しくありません。関数型プログラミングは、状態を回避することではなく、参照の透過性についてです(参照の透過性を確保するために状態を適切に処理する必要があります)。Haskell 状態と変異を許可します。それは、それについて推論するためのさまざまな(論じられるかもしれませんが、より良い)ツールを提供するだけです。
ジョルジオ

38

プログラミングの首謀者:主要なプログラミング言語の作成者との会話

[ハスケル]

なぜ関数型プログラミング言語が主流になったと思いませんか?

ジョン・ヒューズ:貧弱なマーケティング!私は宣伝を意味するのではありません。それはたくさんありました。私は支配するターゲット市場ニッチの慎重な選択を意味し、その後、そのニッチに対処する最も効果的な方法で関数型プログラミングを作るための断固とした努力が続きます。80年代の幸せな日には、関数型プログラミングはすべてに適していると思っていました。ブランドとは何ですか?これは、John LaunchburyがICFPでの招待講演で非常に明確に説明した問題です。Galois Connectionsは、そのブランドが「関数型言語のソフトウェア」であるときにほぼ破綻しましたが、「高保証ソフトウェア」に注力して以来、その強さはますます強まっています。

多くの人々は、技術革新がどのように発生するかを理解しておらず、より優れた技術が単独ですべて支配的になることを期待しています(「より優れたネズミ捕り」効果)。しかし、世界はそうではありません。


36
Haskell:20年後、一夜で成功しました!
ジュリエット

リンクをたどり、Grady Boochのかなり面白いdisのレビューを読んでください。ブーチが誰であるかはわかりませんが、とにかく笑いました。
fearofawhackplanet 2010年

4
Grady Boochは、最終的にはJacobsonとRumbaughとともに、UMLである嫌悪の責任を負っています。
私の正しい意見だけ正しい

27

標準的な答えは、どちらも他のものに取って代わるものではなく、そうすべきではないということです。これらは、長所と短所の異なるセットを持つさまざまなツールであり、どちらのアプローチに優位性があるかは、プロジェクトや利用可能な人材プールなどのその他の「ソフト」問題によって異なります。

関数型プログラミングが他のスタイルよりも選択されている場合、マルチコアによる同時実行の増加により、(開発プロジェクトのグローバルセットの)パーセンテージが増加すると思います。

今日の専門人材プールの大部分は、命令型のオブジェクト指向テクノロジーに最も慣れているため、今日では珍しいと思います。たとえば、私は商用プロジェクトの言語としてJavaを2回以上選択しました。これは十分なことで、論争の余地がなく、その中で(十分に)プログラミングできる人々が不足することはないことを知っています。


これは非常に洞察に富み、楽しく実用的です。間違いなく、私がこの質問にあらゆる形で見た中で最良の答えです。
Benson、

多分両方とも一流の市民である言語が人気になるでしょう。
Kevin Kostlan 2014年

1
110%同意します。何度かFPに乗り込もうとしたが、数週間後に継続する意志を失った。私は手続き的に30年以上プログラミングしており、命令型プログラミングには慣れています。これは、IT業界全体に当てはまります。変化は簡単にも早くも起こりません。
Richard Eng 2015年

26

関数型プログラミングの利点にもかかわらず、命令型プログラミングとオブジェクト指向プログラミングが完全になくなることは決してありません。

命令型オブジェクト指向プログラミングは、問題とその解決策を段階的に説明したものです。そのため、理解しやすくなります。関数型プログラミングは少しあいまいな場合があります。

最終的に、有用なプログラムには常に副作用があります(実際の出力をユーザーに提供して消費させるなど)。そのため、最も純粋な関数型言語では、時々命令型の世界に足を踏み入れる方法が依然として必要です。

現在の最先端技術では、命令型言語(C#など)は機能の世界(ラムダステートメントなど)から機能を借用し、その逆も同様です。


3
OOPは、命令型プログラミングのある種のサブセットではありませんか?
pankrax

9
OOPはスーパーセットです。C ++はCにあるようOOPが不可欠にある
ロバート・ハーヴェイ

10
OOPが必ずしも命令型プログラミングに依存しているとは思いません。ClojureまたはCLOSを見てください。どちらも機能的ですが、オブジェクト指向です。
Gabe

9
オブジェクト指向言語は必須である傾向がありますが、そうである必要はありません。OCamlは強力な(純粋ではありませんが)関数型言語であり、その存在理由は全体がOOです。
チャック

7
OOPが命令型プログラミングのスーパーセットである理由がわかりません。すべての命令コードがOOPであるわけではなく、すべての機能コードが非OOPであるわけではありません。私はむしろ、OOPは、空力翼がレーシングカー、飛行機、ロケット、または冷却ファン、または風車などの命令型プログラミングおよび関数型プログラミングであると言います。 1対1接続。
セバスチャンマッハ

21

ね?

Smalltalkは、昔は素晴らしいオブジェクト指向システムでした。なぜオブジェクト指向プログラミングが引き継がれていないのですか?まあ、それは持っています。それはSmalltalkのようには見えません。メインストリーム言語は、C ++、Java、C#などでSmalltalkのようになり続けています。ファッションやスタイルの変更は何よりも遅いため、OOが主流になったとき、OOの一部を古い言語に接着して、Cのように飲み込むことができるようにしました。 。

機能は同じです。Haskellは素晴らしい関数型言語でした。しかし、今日のCライクな構文を使用するメインストリームプログラマーの数は、20年前よりもさらに多くなっています。したがって、Cのように見える必要があります。完了:LINQ式を見て、機能していないことを教えてください。


2
興味深い点ですが、主流の言語はどのようにしてSmalltalkのようになっていますか?たとえば、C ++、Java、C#は、メッセージ送信に基づいていません。これは、Smalltalkパラダイムの最も重要な部分(私は信じています)です。
ジョナサンスターリング

4
ジョナサン:Smalltalkの機能を選択して、C ++(最も古い)で最も弱く、JavaでOK、C#でどのように機能が弱いかを観察してください。たとえば、GC(Java / C#のみ)、オートボクシング(後のJava / C#のみ)、クロージャー(C#のみ)、およびリフレクション(Javaに存在、C#のほうが適切)。メッセージパッシングが必要な場合は、C#4を参照してくださいdynamic。これはこれらの機能の中で最もSmalltalk-yであるため、これらの3つの言語のうち最新の最新バージョンにのみ存在することは驚くに値しません。:-)
Ken

Javascript、python、およびrubyは、Javascript、python、およびrubyが実際にどのように機能しているかを示す良い例です
nafg

15

命令型言語が普及しているのは、それが多くの人々に慣れているからです。関数型プログラミングモデルも命令型プログラミングモデルも、他のものよりも曖昧でも学術的でもありません。実際、それらは補完的なものです。

あるポスターは、命令型コードは関数型プログラミングコードよりも理解しやすいと述べています。これは、読者が命令型コードを既に見た場合、特に前の例が同じ「ファミリ」の一部である場合(C / C ++、Perl、PHP、Javaなど)にのみ当てはまります。私はそれがために本当だと主張しません任意の命令型言語。極端な例として、JavaとForthを比較します。

一般の人には、HypertalkやSQLなどの冗長言語を除いて、すべてのプログラミング言語は解読できない意味不明なものです。(注目すべきことに、SQLは宣言型および/または関数型言語であり、非常に人気があります。)

最初からLisp-yまたはHaskell-yの言語でトレーニングを受けていたとしたら、関数型プログラミング言語は完全に正常であると考えるでしょう。


「1つのポスターは、命令型コードは関数型プログラミングコードよりも理解しやすいと述べています。これは、読者がすでに命令型コードを見ている場合にのみ当てはまります。特に、前の例が同じ「ファミリ」の一部である場合(C / C ++など) Perl、PHP、Java)」:非常に真実(+1):私がプログラミングを始めたとき、PascalとCの学習に費やした労力を覚えています。そして、これらの言語を使った経験があるので、Scala、Haskell、Schemeを読むのはどれほど簡単か。
Giorgio

2
私がまだ可変状態を有用だと考える唯一の理由は、高速なコード(コピーなし)を簡単に記述できることです。しかし、その理由は、十分な関数型プログラミングがわからないことと、状況の90%で、可変状態を使用せずに高速関数コードを記述できることです。
Giorgio

3
計算を体系化するために最も広く使用され、長期間使用される環境の1つがスプレッドシートです。基本的に、名前付き変数ではなくセルを使用した関数型プログラミング環境。一般的に、人々は本質的にプログラムを一連のステップとして考えているとは思わない。プログラマーは、多岐にわたる命令型言語に浸っていたのかもしれません。
jpnp 2014年

14

あなたはすでに十分な回答を得ているので、まだ言及していないいくつかのことだけを述べます。

まず、そして(私の心の中で)何よりも、手続き型言語はそれらの共通性の程度から大きな恩恵を受けてきました。たとえば、主流の手続き型(またはOO)言語のほとんどすべてをほとんどすべての程度知っている人なら誰でも、他のほとんどの言語を適切に読むことができます。私は積極的にJava、C#、Cobol、Fortran、Basicでの作業を避けています(ほんの数例のみ)が、それらのどれでもかなり上手に読むことができます-実際、ほぼ毎日、それらを使用する人々としても同様です。

機能面では、それはだ非常に少ない真。ほんの一例として、Schemeをかなり合理的に書くこともできますが、それはOcamlやHaskellの読み取りにはほとんど役に立ちません(ほんの数例のみ)。単一のファミリ(たとえば、Scheme対Common Lisp)内でさえ、1つに精通していることは、他のものにほとんど同じように変換されないようです。

関数コードがより読みやすいという主張は、狭い範囲の条件下でのみ当てはまる傾向があります。言語に非常に精通している人にとって、読みやすさは確かに優れています-しかし、他の人にとっては、それはしばしば存在しないものの隣にあります。さらに悪いことに、手続き型言語の違いは主に構文によるものであり、したがって比較的簡単に習得できますが、関数型言語の違いははるかに根本的なことが多いため、実際に理解するにはかなりの研究が必要です(たとえば、Lispを知ることはモナドを理解する上でほとんど役に立ちません)。

もう1つの重要な点は、関数型プログラムは手続き型プログラムよりも短いという考えは、多くの場合、セマンティクスよりも構文に基づいているということです。(一例として)Haskellで書かれたプログラムは、しばしば非常に短いですが、機能的であることは、その一部です。Haskellの構文が比較的簡潔であるというだけの場合は、非常に重要です。

純粋な関数型言語は、簡潔なソースコードでAPLと競合できるものはほとんどありません(ただし、公平に言うと、APLはより高いレベルの関数の作成もサポートしているため、他のいくつかのケースほど大きな違いはありません)。反対に、AdaとC ++(ほんの数例のみ)は、特定のタスクを実行するために必要な操作の数に関して非常に競争力がありますが、構文は(少なくとも通常は)かなり冗長です。


素晴らしいコメント!私は心から同意します。ほとんどの手続き型言語は、私がほんの一部の本当の専門家であるにもかかわらず、読みやすく理解しやすいと思います。FP言語について同じことを言うことはできません。
Richard Eng 2015年

1
もう1つの重要な点は、どのパラダイムでも、初心者から教祖まで、幅広い専門知識を見つけることです。FPコードは専門家にとっては簡単に読みやすく、理解しやすいかもしれませんが、中途半端なプログラマーは依然として苦労するでしょう。エキスパートは通常、FPコミュニティのごく一部です。
Richard Eng 2015年

11

認識された必要なし

ジョン・バッカスのチューリング賞の講演で、「プログラミングはフォン・ノイマン・スタイルから解放されますか?」

彼の反応:「フォンノイマンスタイルから解放されたくないのかもしれません。」


10

関数型プログラミングがまだ引き継がれていないのはなぜですか?

機能的なものは、あるものにとってはより良く、他のものにとってはより悪いので、決して「引き継ぐ」ことはありません。しかし、現実の世界ではすでに広く普及しています。

ステートレスプログラム; 副作用なし

ステートレスプログラムはテストが簡単です。これは現在広く認められており、産業界でしばしば利用されています。

並行性; マルチコアテクノロジーの進歩により、非常に優れたプレイを実現プログラムは通常短くなり、場合によっては読みやすくなります生産性が向上します(例:Erlang)

並行処理と並列処理を融合しています。

並行性は、通信順次プロセス(CSP)を使用して効果的に実行できます。CSP内のコードはローカル状態を変更できますが、それらの間で送信されるメッセージは常に不変である必要があります。

純粋に関数型のプログラミングはマルチコアでは非常にうまく機能しません。これは、キャッシュが使いにくいためです。コアは共有メモリをめぐって競合し、並列プログラムはスケーリングしません。

なぜ企業が関数型言語で使用されているプログラムや関数型言語で書かれたプログラムがまだ「まれ」であるのですか?

Scalaは関数型言語と見なされることがよくありますが、今日世界で最も人気のある言語の1つであるC#よりも機能的ではありません。

関数型プログラミングの利点を検討するときに、依然として命令型プログラミング言語を使用しているのはなぜですか?

純粋な関数型プログラミングには多くの重大な欠点があるため、Lisp、Scheme、SML、OCaml、Scala、C#などの不純な関数型言語を使用しています。


7

関数型プログラミングが私のプロジェクトにもたらす可能性があることについて考えるとき、私はいつも同じ考えの道をたどっています。

  1. 関数型プログラミングの利点を最大限に活用するには、遅延が必要です。はい、厳密な関数型言語はありますが、関数型プログラミングの本当の利点は、厳密なコードではうまくいきません。たとえば、Haskellでは、一連のレイジー操作をリストに作成し、それらを連結してリストに適用するのは簡単です。例えば。op1 $ op2 $ op3 $ op4 $ someList。リスト全体が作成されるわけではないことはわかっています。内部的には、要素を1つずつ処理する優れたループを取得します。これにより、本当にモジュール式のコードを書くことができます。2つのモジュール間のインターフェースには、潜在的に膨大なデータ構造の引き渡しが含まれる可能性がありますが、構造を常駐させる必要はありません。

  2. しかし、怠惰があると、メモリ使用量を推論するのが難しくなります。Haskellコンパイラフラグを変更すると、アルゴリズムが使用するメモリ量がO(N)からO(1)に頻繁に変更されますが、変更されない場合もあります。利用可能なすべてのメモリを最大限に利用する必要があるアプリケーションがある場合、これは実際には受け入れられません。また、すべてのメモリを必要としないアプリケーションであっても、それは適切ではありません。


怠惰は、デバッグとの相互作用も理想的ではありません。
ブライアン、

3
私が他の言語で追いかけているバグの多くは、参照の透過性の欠如に関連していることがわかったので、デバッグが問題になることはあまりありませんが、問題になることもあります。
sigfpe 2010年

6

2つのこと:

  1. テクノロジーがどれほど優れていても、時間がかかるだけです。FPの背後にあるアイデアは約70年前のものです。しかし、ソフトウェアエンジニアリング(トレンチ、業界)での主流の使用法は、おそらく10年未満です。人種的に新しい考え方を採用するよう開発者に依頼することは可能ですが、時間がかかるだけです(多くの場合、何年も)。たとえば、OOPは1980年代初頭に本当に主流になりました。しかし、それは1990年代後半までは優勢性を獲得しませんでした。
  2. テクノロジーが大きくなる前に、テクノロジーの強みに直面するように強いられる必要があります。現在、人々は並列処理を利用しないツールを使用しており、物事は大丈夫です。並列処理を使用しないアプリが耐え難いほど遅くなると、そうなると、多くの人が並列処理ツールの使用を余儀なくされ、FPが人気を集める可能性があります。これはFPの他の強みにも当てはまるかもしれません。

3
FPはコードの再利用が非常に得意です。おそらくOOより良いでしょう。私は仕事で数回、別のタイプに移行し、新しいシステムに対処する必要があり、それは簡単でした。
nlucaroni

@Freddy Riosおよび@nlucaroni。誤解を解消するためにコメントを書き換えました。
Phil
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.