web-dev-qa-db-ja.com

Pythonで関数型プログラミングを実行できる場合、特定の関数型プログラミング言語が必要ですか?

ジェネレータとラムダを使用して、Pythonで関数型プログラミングを実行できます。 Rubyでも同じことができます。

だから問題は、なぜErlang、Haskell、Schemeなどの特定の関数型プログラミング言語が必要なのかということです。これらの特定の関数型プログラミング言語が提供するものと異なる点はありますか?関数型プログラミングにPythonを使用できないのはなぜですか?

22
Joshua Partogi

私は個人的にPythonと関数型のプログラミングスタイルの両方のファンであるので、質問に感謝します。Pythonには長い経歴があり、最近Haskellを学び始めたので、これらの言語間の違いについての機能的な観点からの個人的な経験に基づいたいくつかのポイントをここに示します。

純度

関数の純粋さ(つまり、副作用がないこと)を原則として気にしない場合でも、コードの読み取りとその理由の理解のしやすさに実際的な影響があります。独自のPython関数で純粋性を維持している場合でも、コンパイラーに純粋性を強制させることと、何よりも、標準ライブラリーを純粋性と不変データ構造の観点から構築することには大きな違いがあります。 。

パフォーマンス

アプリケーションドメインが何であるかによって、パフォーマンスに関心がある場合とない場合がありますが、静的型付けと保証された純粋性により、コンパイラは、Pythonや他の動的言語(ただし、私は、PyPyが素晴らしい進出をしていることを認めなければなりません。たとえば、LuaJITは奇跡的なものとの国境を接しています。

末尾呼び出しの最適化

パフォーマンスに関連しますが、少し異なります。ランタイムのパフォーマンスをあまり気にしなくても、末尾呼び出しの最適化(特に末尾再帰)を行わないと、Python)でアルゴリズムを実装する方法が制限され、スタックの制限に達することはありません。

構文

これが、Pythonを関数スタイルで使用するのではなく、実際の関数型言語を検討し始めた最大の理由です。Pythonには一般に非常に表現力豊かな構文には、関数型コーディングに固有の弱点があります。次に例を示します。

  • ラムダ関数の構文はかなり冗長であり、それらが含むことができるものに制限があります
  • 関数の構成に構文糖衣はありません。つまり、_f = g . h_とf = lambda *arg: g(h(*arg))
  • 部分的なアプリケーション、つまり_f = map g_とf = functools.partial(map, g)には構文糖がない
  • より高次の関数でインフィックス演算子を使用するための構文糖、つまりsum = reduce (+) lstsum = reduce(operator.add, lst)
  • 関数の引数に対するパターンマッチングやガードはありません。これにより、再帰の終了条件や非常に読みやすい構文を使用した境界のケースを簡単に表現できます。
  • 関数呼び出しの場合、角括弧はオプションではありません。ネストされた呼び出しには構文上の砂糖はありません。これは好みの問題だと思いますが、特に関数コードでは、関数呼び出しをチェーンするのが一般的であり、y = func1(func2(func3(x)))よりも_y = func1 $ func2 $ func3 x_の方が読みやすいと思います。 。
20
shang

これらは最も重要な違いです:

ハスケル

  • 遅延評価
  • マシンコードにコンパイル
  • 静的型付けは、関数が純粋であることを保証します
  • 型推論

HaskellおよびErlang

  • パターンマッチング

Erlang

  • 並行性、軽量プロセスのアクターモデル

スキーム

  • マクロ

すべての言語

  • 実際のクロージャー(Rubyにはクロージャーがあります。pythonは議論できるかどうか、コメントを参照してください)
  • 関数型プログラミングスタイル(不変コレクション、マップ、フィルター、フォールドなど)に適した標準ライブラリ
  • 末尾再帰(これは一部の非関数型言語でも見つかります)

また、OOと関数型プログラミングを新しい方法で融合したSML、Ocaml、F#、ScalaなどのMLファミリの言語もご覧ください。これらのすべての言語には、独特の興味深い機能があります。

28
Kim

「関数型言語」が何であるかを正確に定義することは困難です。リストした言語のうち、純粋に機能するのはHaskellだけです(他のすべては何らかのハイブリッド手法を採用しています)。ただし、関数型プログラミングに非常に役立つ特定の言語機能があり、RubyおよびPythonには、 FP。これが私の個人的なチェックリストです。

  1. ファーストクラスの関数 および クロージャー (Ruby、Python、およびすべてのあなたがリストした他の人はこれを持っています)。
  2. 保証付き 末尾呼び出しの最適化 (Erlang、Haskell、Scala、Schemeにはありますが、Python、Ruby、Clojure(まだ)はありません)。
  3. 言語および標準ライブラリでの immutability のサポート(これは、リストしたすべての「関数型言語」が(Schemeを除いて)持っているものの、= RubyおよびPythonしないでください)。
  4. 参照的に透過的な (または純粋な)関数の言語レベルのサポート(現在のところ、Haskellだけがこれを持っています)。

(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はこれを最大限に利用していますが、他の関数型言語については、それらがそうであるかどうかについては十分に知りません。

つまり、FPテクニックは、ほとんどすべての言語(Javaを含む)でも使用できます。たとえば、Googleの MapReduce は関数型のアイデアに触発されていますが、私が知る限り、彼らは大規模なプロジェクトに「関数型」言語を使用していません(主にC++、Java、Pythonを使用していると思います)。

19
shosti

あなたが言及する言語は非常に異なります。

Python and Rubyは動的に型付けされる言語ですが、Haskellは静的に型付けされます。Erlangは並行言語であり、Actorモデルを使用し、他のすべての言語とは大きく異なりますあなたが言及します。

PythonとRubyには多くの命令構造がありますが、Haskellのようなより純粋な関数型言語では、すべてが何かを返します。つまり、すべてが関数です。

11
Jonas

いつものようにパーティーに遅れますが、とにかく言います。

関数型プログラミング言語は、許可関数型プログラミングではありません。その定義で言えば、ほとんどすべての言語が関数型プログラミング言語です。 (偶然にも同じことがOOPにも当てはまります。必要に応じて、CでOOPスタイルで書き込むことができます。したがって、ロジックによると、CはOOP =言語。)

関数型プログラミング言語を作るものはそれがそうではありません許可するプログラミングのようにあなたがそうすることができるものです簡単に。それが鍵です。

したがって、Pythonにはラムダ(信じられないほど貧弱な閉鎖のようなものです)があり、「マップ」や「フォールド」などの関数ライブラリに表示されるいくつかのライブラリ関数を提供します) 。これは、関数型プログラミング言語にするのに十分ではありませんが、適切な関数型スタイルで一貫してプログラムすることは不可能から困難です(そして言語確かにはこのスタイルを強制しません!)そのコアPythonは状態と状態操作操作に関係する命令型言語であり、これは単に矛盾しています関数型言語の式と式の評価セマンティクス。

Python(またはRuby(または選択した言語を挿入)))が「関数型プログラミング」を実行できるのに、なぜ関数型プログラミング言語があるのですか?Python 、他は適切な関数型プログラミングを行うことができません。

あなたはすることができますJava(例えば http://functionaljava.org/ )。 オブジェクト指向プログラミングをCで行うこともできます これは、その慣用的ではありません。

したがって、確かに絶対にErlang、Haskell、Scheme、または特定のプログラミング言語は必要ありませんが、それらはすべて異なるアプローチと異なるトレードオフを表しています。一部のタスクをより簡単に、より困難にします。何を使用するかは、達成したいことに依存します。

6
Joonas Pulakka

この質問は、無限の数の言語とパラダイムに適用できます。

  • 誰もがC++を使用しているのに、なぜ他の汎用言語が必要なのでしょうか。
  • Javaはとても素晴らしいOO言語なので、なぜ他のOO言語が存在するのですか?
  • Perlは素晴らしいスクリプト言語なので、なぜPythonが必要なのでしょうか。
  • やった、やった、やった

特定の理由により、すべてではないにしてもほとんどの言語が存在します。彼らは、誰かが現在の言語が満たされていない、または不十分に満たされている必要があるために存在しています。 (もちろん、これはすべての言語に当てはまるわけではありませんが、よく知られているほとんどの言語に当てはまると思います。)たとえば、pythonは、もともとAmoeba OSとのインターフェースとして開発されました[- 12 ]およびErlangは、テレフォニーアプリケーションの開発を支援するために作成されました[]。 [別の関数型言語が必要ですか?]は、[insert-name-of-someone-who-knows-how-to-design-languages]が気に入らなかったため、python 。

それは私が答えを考えていることを大体要約します。 pythonを使用すると、関数型言語で実行できることは何でもできますが、本当にしたいですか?Cで実行できるすべてのこと、アセンブリで実行できますが、実行したいですか?さまざまな言語が常にさまざまなことを行うのに最適であり、それが本来あるべき姿です。

4
cledoux

関数型プログラミングは、特定の言語機能についてだけでなく、デザインパラダイムについても同じです。または、言い換えると、ラムダとマップ関数は関数型プログラミング言語では作成できません。 PythonおよびRubyには、関数型プログラミング言語に触発されたいくつかの機能がありますが、一般的には非常に命令的な方法でコードを記述します(Cのようなものです: CでOOのようなコードを書くことができますが、CをOO言語)であると真剣に考える人は誰もいません。

見てください:関数型プログラミングはラムダ、map、または高階関数だけではありません。 designについてです。 「真の」関数型プログラミング言語で書かれたプログラムは、関数の構成によって問題を解決します。 RubyまたはPythonで記述されたプログラムはFPに似た機能を使用する場合がありますが、通常、一連の合成関数のようには読みません。

2
mipadi

あなたが言及した各関数型言語は、特定のニッチに非常によく適合し、それぞれが奨励する慣用的なパターンは、Pythonで達成できない巨大なライブラリでない限り、特定のタスクに非常に適しています。ヘルパーモジュールの1つです。そのようなニッチな卓越性の最も明白なものは、Erlangの同時実行モデルです。他のモデルにも同様の強みがあります。

0
davidk01

Lambda-calculus、LISP、Schemeで利用可能なすべての概念はPythonでも利用できるため、そうです、その中で関数型プログラミングを実行できます。それが便利かどうかは、状況と好みの問題です。

LISP(または他の関数型言語)インタープリターはPython(Ruby、Scala)で簡単に作成できます(これはどのくらいの意味ですか?)。純粋に関数型を使用してPythonのインタープリターを作成できますが、多くの作業が必要になります。 「機能的」言語でさえ、今日ではマルチパラダイムです。

この古くて美しい本 は、関数型プログラミングの本質が何であるかについての答えのほとんど(すべてではありません)を持っています。

0
Apalala