ジェネレーターとラムダを使用して、Pythonで関数型プログラミングを行うことができます。Rubyでも同じことを実現できます。
質問は次のとおりです。Erlang、Haskell、Schemeなどの特定の関数型プログラミング言語が必要なのはなぜですか?これらの特定の関数型プログラミング言語が提供するものと異なるものはありますか?関数型プログラミングにPythonを使用できないのはなぜですか?
ジェネレーターとラムダを使用して、Pythonで関数型プログラミングを行うことができます。Rubyでも同じことを実現できます。
質問は次のとおりです。Erlang、Haskell、Schemeなどの特定の関数型プログラミング言語が必要なのはなぜですか?これらの特定の関数型プログラミング言語が提供するものと異なるものはありますか?関数型プログラミングにPythonを使用できないのはなぜですか?
回答:
私は個人的にPythonと関数型プログラミングの両方の大ファンなので、質問に感謝します。Pythonのバックグラウンドが長く、最近Haskellを学び始めたので、機能的な観点から、これらの言語の違いに関する個人的な経験に基づいたいくつかのポイントを示します。
純度
関数の純粋さ(つまり、副作用がないこと)をおもしろいものとして気にしなくても、コードの読みやすさとその理由について実用的な効果があります。独自のPython関数で純度を維持していても、コンパイラに純度を強制させることと、何よりも純度と不変のデータ構造に基づいて構築された標準ライブラリを持つことには大きな違いがあります。
性能
アプリケーションドメインに応じてパフォーマンスを気にする場合としない場合がありますが、静的型付けと保証された純度により、Pythonや他の動的言語と比較して、コンパイラはより多くの作業を行うことができます(PyPyが優れていることは認めざるを得ませんが)そして、例えばLuaJITは奇跡に隣接しています)。
テールコール最適化
パフォーマンスに関連していますが、わずかに異なります。実行時のパフォーマンスをあまり気にしない場合でも、末尾呼び出しの最適化(特に末尾再帰)がないと、スタック制限に達することなくPythonでアルゴリズムを実装する方法が制限されます。
構文
これが、関数型スタイルのPythonを使用するのではなく、「実際の」関数型言語を検討し始めた最大の理由です。Pythonには一般に非常に表現力豊かな構文があると思いますが、関数型コーディングに特有の弱点がいくつかあります。例えば:
f = g . h
vs. 用の構文糖f = lambda *arg: g(h(*arg))
f = map g
vs.f = functools.partial(map, g)
sum = reduce (+) lst
対sum = reduce(operator.add, lst)
y = func1 $ func2 $ func3 x
読みやすくなることがわかりy = func1(func2(func3(x)))
ます。これらは最も重要な違いです:
ハスケル
ハスケルとアーラン
アーラン
スキーム
すべての言語
また、SML、Ocaml、F#、ScalaのようなMLファミリーの言語を見てください。これは、オブジェクト指向と関数型プログラミングを新しい方法で融合します。これらのすべての言語には、独自の興味深い機能があります。
「関数型言語」が何であるかを正確に定義することは困難です。リストした言語のうち、純粋に関数型であるのはHaskellのみです(他のすべては何らかのハイブリッドアプローチを採用しています)。ただし、関数型プログラミングに非常に役立つ特定の言語機能があります。また、RubyとPythonには、FPにとって非常に優れた環境となるための十分な機能がありません。重要な順に私の個人的なチェックリストがあります:
(1)の必要性は明白なはずです-高階関数は、一流の関数なしでは非常に困難です。RubyとPythonがFPに適した言語であると人々が話すとき、彼らは通常これについて話します。ただし、この特定の機能は必要ですが、FPに適した言語にするためには十分ではありません。
(2)Schemeが発明されて以来、FPの伝統的な必要性でした。TCOがなければ、スタックオーバーフローが発生するため、FPの基盤の1つである深い再帰でプログラミングすることはできません。これを持たない唯一の「一般的な」機能言語は(JVMの制限のため)Clojureですが、ClojureにはTCOをシミュレートするためのさまざまなハックがあります。(FYI、Ruby TCOは実装固有ですが、Pythonは特にそれをサポートしていません。)TCOが保証されなければならない理由は、実装固有である場合、深い再帰関数がいくつかの実装で壊れてしまうためです。それらをまったく使用します。
(3)は、現代の関数型言語(特にHaskell、Erlang、Clojure、Scala)にある大きなものであり、RubyとPythonにはないものです。あまり詳しく説明しなくても、保証された不変性は、特に同時状況でのバグのクラス全体を排除し、永続的なデータ構造のようなきちんとしたものを可能にします。言語レベルのサポートなしでこれらの利点を活用することは非常に困難です。
(4)は、私にとって、純粋に機能的な言語(ハイブリッド言語とは対照的に)について最も興味深いものです。次の非常に単純なRuby関数を考えてみましょう。
def add(a, b)
a + b
end
これは純粋な関数のように見えますが、演算子のオーバーロードのために、いずれかのパラメーターを変更したり、コンソールへの印刷などの副作用を引き起こす可能性があります。誰かが+
副作用を引き起こすために演算子をオーバーロードすることはまずありませんが、言語は保証を与えません。(Pythonにも同じことが当てはまりますが、この特定の例には当てはまりません。)
一方、純粋に関数型の言語では、関数が参照的に透過的であるという言語レベルの保証があります。これには多くの利点があります。純粋な関数は簡単にメモできます。グローバル状態に依存せずに簡単にテストできます。また、関数内の値は、並行性の問題を心配することなく、遅延評価または並行して評価できます。Haskellはこれを最大限に活用していますが、他の関数型言語について十分な知識がなく、それらが機能するかどうかを知ることができません。
とはいえ、ほぼすべての言語(Javaを含む)でFPテクニックを使用することは可能です。たとえば、GoogleのMapReduceは機能的なアイデアに触発されていますが、私が知る限り、彼らは大規模なプロジェクトに「機能的な」言語を使用していません(主にC ++、Java、Pythonを使用していると思います)。
あなたが言及する言語は非常に異なっています。
PythonとRubyは動的に型付けされた言語ですが、Haskellは静的に型付けされています。Erlangは同時実行言語であり、Actorモデルを使用しますが、他のすべての言語とは非常に異なります。
PythonとRubyには多くの必須の構成要素がありますが、Haskellのようなより純粋な関数型言語では、すべてが何かを返します。つまり、すべてが関数です。
いつものようにパーティーに遅れましたが、とにかく物事を言うつもりです。
関数型プログラミング言語は、 関数型プログラミング許可。私たちがその定義に従えば、ほとんどすべての言語は関数型プログラミング言語です。(偶然、OOPにも同じことが当てはまります。必要に応じてCでOOPスタイルで記述できます。したがって、ロジックによれば、CはOOP言語です。)
関数型プログラミング言語を作るのは、プログラミングを許可するものではなく、簡単にプログラミングできるようにするものですです。それが鍵です。
そのため、Pythonにはラムダ(非常に貧弱なクロージャのような問題)があり、「map」や「fold」などの機能ライブラリにあるライブラリ関数をいくつか提供します。それは適切な機能に一貫プログラムに不可能に困難であるため、これは、しかし、それを関数型プログラミング言語を作るのに十分ではないスタイルでそれ(と言語確かにこの型を強制しません!)。その中心となるPythonは、状態および状態操作操作に関係する命令型言語であり、これは関数型言語の式および式評価のセマンティクスと単純に対立しています。
では、Python(またはRuby(または選択した言語を挿入))が「関数型プログラミングを行う」ことができるのに、なぜ関数型プログラミング言語があるのでしょうか。Pythonなどは適切な関数型プログラミングを行うことができないためです。それが理由です。
Javaで関数型プログラミングを行うことができます(http://functionaljava.org/などを参照)。Cでオブジェクト指向プログラミングを行うこともできます。それはただの慣用句ではありません。
したがって、実際には、Erlang、Haskell、Scheme、または特定のプログラミング言語は絶対に必要ではありませんが、それらはすべて異なるアプローチと異なるトレードオフを表し、いくつかのタスクをより簡単にし、より難しくします。使用すべきものは、何を達成したいかによって異なります。
この質問は、無数の言語とパラダイムに適用できます。
特定の理由ですべてではないにしても、ほとんどの言語が存在します。誰かが現在の言語が満たされない、または不十分に満たされる必要があったからです。(もちろん、これはすべての言語には適用されませんが、私はそれがよく知られている言語のほとんどに適用される感じ。)例えば、Pythonのは、もともとアメーバOSとのインターフェイスに開発された[ 1、2 ]とErlangのが助けに作成されましたテレフォニーアプリケーションの開発[ 3 ]。したがって、「なぜ別の関数型言語が必要なのか」という質問に対する1つの答えです。[言語を設計する方法を知っている人の名前を挿入]がpythonのやり方を好まなかったため、単純にできます。
それは私が答えだと思うことをかなり要約しています。関数型言語でできることはpythonで何でもできますが、本当にしたいですか?Cでできることはすべて、アセンブリで行うことができますが、したいですか?さまざまな言語は常にさまざまなことを行うのに最適であり、それはそうあるべき方法です。
関数型プログラミングは、特定の言語機能と同じくらい設計パラダイムに関するものです。または、別の言い方をすれば、ラムダとマップ関数は関数型プログラミング言語が作成するものではありません。PythonとRubyには、関数型プログラミング言語に触発された機能がいくつかありますが、通常は非常に命令的な方法でコードを記述します。(Cのようなものです。Cでオブジェクト指向のようなコードを書くことができますが、Cをオブジェクト指向言語と真剣に考えている人はいません。)
見てください:関数型プログラミングは、ラムダやmap
、または高階関数だけではありません。それはデザインについてです。「真の」関数型プログラミング言語で書かれたプログラムは、関数の構成によって問題を解決します。RubyまたはPythonで書かれたプログラムはFPに似た機能を使用する場合がありますが、通常は合成された関数のセットのようには読みません。
ラムダ計算、LISP、およびSchemeで使用可能なすべての概念はPythonで使用できるため、その中で関数型プログラミングを実行できます。それが便利かどうかは、コンテキストと好みの問題です。
Python(Ruby、Scala)でLISP(または他の関数型言語)インタープリターを簡単に書くことができます(その量は?)。Pythonのインタープリターは、純粋に機能的なものを使用して作成できますが、多くの作業が必要になります。「関数型」言語でさえ、今日ではマルチパラダイムです。
この古くて美しい本には、関数型プログラミングの本質とは何か(ほとんどではありませんが)の答えがあります。
eval()
関数を提供します。これはコードがデータであるために必要なものですが、さらに進んでいます。LISPのように、ランタイム環境のほとんどを変更できます。
eval()
はランタイムメタプログラミングです。時には便利ですが、非常に高価です。Lispマクロは異なり、コンパイル時のメタプログラミングです。Pythonでは、使用可能な形式では使用できません。
Pythonは機能しないスタイルでもプログラミングできるため、FPの純粋主義者には十分ではありません。しかし、より実用的なコーダーは、それについて独断的でなくても、機能的なスタイルの利点を享受できます。
「機能的なプログラマーはむしろ中世の修道士のように聞こえ、人生の喜びを否定し、それが彼を高潔にすることを望んでいます。物質的な利益にもっと関心がある人にとって、これらの「利点」はあまり説得力がありません。機能的なプログラマーは、大きな物質的利益があると主張します…[しかし]これは明らかにばかげています。割り当てステートメントを省略すると、そのような大きな利点がもたらされた場合、FORTRANプログラマーは20年間それを行っていたでしょう。機能がどれほど悪くても、機能を省略することで言語をより強力にすることは論理的に不可能です。」
-ジョンヒューズ、関数型プログラミングが重要な理由
goto
はひどいです。
call-with-current-continuation
。