web-dev-qa-db-ja.com

関数型プログラミングの中心的な概念は何ですか?

オブジェクト指向プログラミングでは、主要な概念は次のとおりです。

  1. カプセル化
  2. 継承、
  3. ポリモーフィズム

関数型プログラミングではそれは何でしょうか?

54
pierrotlefou

関数型プログラミングに不可欠な概念は何かについてのコミュニティの合意はありません。 なぜ関数型プログラミングが重要か(PDF) の中で、John Hughesは、それらが高次関数であり、遅延評価であると主張しています。 ヘアーシャツを着ている:Haskellの回顧展 では、Simon Peyton Jonesは本当の本質は怠惰ではなく純粋であると述べています。リチャードバードは同意するでしょう。しかし、副作用のあるプログラムを完全に喜んで書いているSchemeプログラマーとMLプログラマーは大勢います。

20年以上関数型プログラミングを実践し、教えてきた人として、関数型プログラミングの中心にあると広く信じられているいくつかのアイデアを紹介します。

  • 適切な字句スコープを持つ入れ子のファーストクラス関数がコアにあります。これは、実行時に無名関数を作成できることを意味します。その自由変数はenclosing関数のパラメーターまたはローカル変数であり、戻り値を取得してデータに入れることができます。構造など。 (これは高次関数の最も重要な形式ですが、一部の高次関数(qsort!など)は、関数型言語ではないCで記述できます)。

  • 関数を他の関数と組み合わせて問題を解決する手段。ジョン・ヒューズほどこれを上手にできる人はいない。

  • 多くの関数型プログラマーは、純粋性(ミューテーション、I/O、例外などの影響からの解放)が関数型プログラミングの中核であると信じています。多くの関数型プログラマはそうしません。

  • Polymorphismは、コンパイラーによって実行されるかどうかにかかわらず、関数型プログラマーのコア値です。紛らわしいことに、C++プログラマはこの概念を「ジェネリックプログラミング」と呼んでいます。コンパイラによってポリモーフィズムが適用される場合、これは通常 Hindley-Milner のバリアントですが、より強力な System F も関数型言語の強力な基盤です。また、Scheme、Erlang、Luaなどの言語を使用すると、静的型システムなしで関数型プログラミングを実行できます。

  • 最後に、大多数の関数型プログラマーは帰納的に定義されたデータ型の値を信じており、「再帰型」と呼ばれることもあります。静的型システムの言語では、これらは一般に「代数データ型」として知られていますが、帰納的に定義されたデータ型は Schemeプログラマー向けに記述された資料 でも見つかります。誘導的に定義された型には通常、パターンマッチングと呼ばれる言語機能が同梱されており、非常に一般的な形式のケース分析をサポートしています。多くの場合、コンパイラは、ケースを忘れた場合に通知します。この言語機能がないとプログラミングしたくありません(一度サンプリングした贅沢が必要になります)。

64
Norman Ramsey

コンピュータサイエンスでは、関数型プログラミングは、計算を数学関数の評価として扱い、状態や可変データを回避するプログラミングパラダイムです。状態の変化を強調する命令型プログラミングスタイルとは対照的に、関数の適用を強調します。関数型プログラミングは、関数定義、関数の適用、および再帰を調査するために1930年代に開発された正式なシステムであるラムダ計算にそのルーツがあります。多くの関数型プログラミング言語は、ラムダ計算の装飾と見なすことができます。 - ウィキペディア

一言で言えば、

  1. ラムダ計算
  2. 高次関数
  3. 不変性
  4. 副作用なし
40
Ben Griswold

あなたの質問への直接の回答ではありませんが、「オブジェクト指向」と関数型プログラミングは必ずしも矛盾していないことを指摘しておきたいと思います。あなたが引用する「コアコンセプト」には、関数型プログラミングにも同様に適用されるより一般的な対応物があります。

カプセル化は、より一般的にはモジュール化です。私がサポートについて知っているすべての純粋に関数型の言語モジュール式プログラミング。副作用によってカプセル化が解除され、純粋な関数には副作用がないであるため、これらの言語は一般的な「OO」よりも優れたカプセル化を実装していると言えます。

より一般的には、継承は論理的含意であり、これは関数が表すものです。正規subclass -> superclassリレーションは一種の暗黙の関数です。関数型言語では、これはtype classesまたはimplicitsで表されます(私は暗黙のうちにこれらの2つの中でより一般的であると考えています)。

「OO」学校の多態性は、サブタイピング(継承)によって実現されます。 parametric polymorphism(別名ジェネリック)と呼ばれる、より一般的な種類のポリモーフィズムがあり、純粋関数型プログラミング言語でサポートされていることがわかります。さらに、「より高い種類」またはより高次のジェネリック(別名タイプコンストラクターポリモーフィズム))をサポートするものもあります。

私が言おうとしているのは、あなたの「OOのコアコンセプト」はOOに固有のものではないということです。私は、anyOOのコアコンセプト。

14
Apocalisp

バンガロール関数型プログラミンググループでの1つの議論で私が与えた答えを繰り返しましょう。

関数型プログラムは関数のみで構成されています。関数は入力から値を計算します。これを命令型プログラミングと対比することができます。プログラムを実行すると、変更可能な場所の値が変化します。つまり、CまたはJavaでは、Xという変数は値が変化する場所を参照します。しかし、関数型プログラミングでは、Xは(場所ではなく)値の名前です。そのXがスコープ内にある場合、Xは同じ値を持ちます(つまり、参照的に透過的です)。 FPでは、関数も値です。これらは、引数として他の関数に渡すことができます。これは高次関数型プログラミングと呼ばれます。高次関数により、驚くほど多様なパターンをモデル化できます。たとえば、LISPのmap関数を見てください。これは、プログラマーがリストのすべての要素に対して「何か」を行う必要があるパターンを表します。その「何か」は、関数としてエンコードされ、引数としてマップに渡されます。

見てきたように、FPの最も注目すべき機能は副作用フリーネスです。関数が入力から値を計算する以上のことを行う場合、それは副作用を引き起こしています。関数は純粋なFPでは許可されていません。副作用のない関数をテストするのは簡単です。テストを実行する前に設定するグローバル状態はなく、テストの実行後に確認するグローバル状態はありません。各関数をテストできます入力を提供し、戻り値を調べるだけで、独立して自動テストを簡単に作成できます。副作用フリーネスのもう1つの利点は、並列処理をより適切に制御できることです。

多くのFP言語は再帰と反復を正しく処理します。それらは、末尾再帰と呼ばれるものをサポートすることによってこれを行います。末尾再帰とは何か-関数がそれ自体を呼び出し、それが最後に行うことである場合、つまり、現在のスタックフレームがすぐに削除されます。つまり、関数が末尾に再帰的に1000回呼び出された場合、スタックは1000深くなりません。これにより、これらの言語では特別なループ構造が不要になります。

ラムダ計算は、FP言語の最も煮詰められたバージョンです。より高いレベルFP Haskellのような言語は、ラムダ計算にコンパイルされます。構文は3つしかありませんがそれでも、抽象化やアルゴリズムを表すのに十分表現力があります。

私の意見では、FPはメタパラダイムと見なす必要があります。ラムダ計算によって提供される単純な関数抽象化を使用して、OOPを含むあらゆるスタイルでプログラムを記述できます。

ありがとう、-Vijay

元のディスカッションリンク: http://groups.google.co.in/group/bangalore-fp/browse_thread/thread/4c2cfa7985d7eab

4
Vijay Mathew

抽象化、式の一部をパラメーター化して関数を作成するプロセス。

アプリケーション、パラメーターを特定の値に置き換えることによって関数を評価するプロセス。

あるレベルでは、これですべてです。

3
Doug McClean