Cで関数型プログラミングを学ぶことができますか?[閉まっている]


9

ここでのコメントディスカッションの結果、Cで関数型プログラミングを学ぶことができるかどうか疑問に思います。


30
できるかできないかに関わらず、すべきではありません
R.マルティーニョフェルナンデス

27
絶対に!最初のステップは、Lispインタプリタを書くことです;-)
Ferruccio

私が正しく理解していれば、問題は 実際の言語をまったく使用せずに、疑似コードを使用してさまざまな概念を学習することについてだったはずです。
SKロジック

@ SK-logic:控えめに言っても、純粋に疑似コードを使ってプログラミングを学んだプログラマはほとんどいません。ほとんどの人は手を汚し、コンパイラ/インタープリタからのエラーメッセージで顔を叩かなければなりませんでした。
sbi

4
@sbi、最高のプログラマーの何人かは、コンパイラーにエラーメッセージがまったくないときにプログラミングを学びました。パンチカードをコーディングするには、コードを実行する前に、何をしているかを少し理解する必要があります。そして言うまでもなく、関数型プログラミングの基礎は、最初のコンピューターが構築されるずっと前に確立されていました。
SKロジック

回答:


21

当然のことながら関数型プログラミングはCで行うことができます。理論的には、関数型プログラミングの原則をCで学ぶこともできますが、この言語では簡単にはできません。

私はあなたがOOPのバックグラウンドを少なくとも持っていると思います。行う場合、Cでポリモーフィズム、ゲッター/セッター、可視性ルールなどを含めてOOPを実行できることを認識しておく必要がありますが、そうすることはかなり困難であり、OOPとCの両方を内部で知る必要があります。引っ張って外します。それはFPとほとんど同じです。

あなたがすべき、(それは彼らが難しい学ぶために作る構文ではありませんそれらのほとんどが驚くほど簡単な構文規則を持っている)、そしてやっていることは関数型プログラミング言語を学ぶ最初で、その後、あなたの新たに獲得知恵はあなたがC.を書く方法に影響を与えてみましょう


リクエストに応じて、FPから学び、C、C ++、Javaなどに適用できるいくつかの事項:

  • 状態、特に共有された変更可能な状態を避ける
  • 純粋な関数を鑑賞する
  • 遅延評価に感謝する
  • 名詞ではなく動詞でモデル化できる
  • 問題に再帰的かつ反復的にアプローチできる
  • 高次関数の使用
  • 関数を別の種類の値と考え、他の値とやり取りして組み合わせることができる
  • オブジェクトベースのポリモーフィズムの代替手段としてのファーストクラス関数の使用

1
C / C ++ / JavaプログラマーがLISPの知識から利益を得ることができる方法の具体的な例を提供できますか。理論的には理にかなっていますが、具体的なものを探しています。
ジョブ

@ジョブ、具体的にどのようなメリットがありますか?それは彼らの心を拡大し、おそらく彼らに過度の可変性のある状態を悪いものとして考えさせるでしょう、あなたはもっと何を求めることができますか?
dan_waterworth、2011年

だから私はこれから結論づけることができますが、Cで(一部の)FPを学ぶことは可能ですが、それを行うのは意味がないということですか?
sbi

@仕事:私は何年も前に学生としてLISPを学んだときにFPを学びました。約10年後、私はテンプレートのメタプログラミングにFPを適用しました。
sbi

1
@sbi、新しい言語と概念を学ぶ私のお気に入りの方法は、それらを実装することです。そしてCは、コンパイラーを実装するためのまともな言語です。だから、そう、あなたはC.でFPを学ぶことができます
SK-ロジック

11

Cをハッキングして、いくつかの機能的な概念を提供できます。

このStackOverflowの質問で、さらに詳しく説明します。しかし、Cで関数型プログラミング(またはその大部分)を実行することは可能であるように見えますが、ハックやコンパイラー拡張など、概念を学ぶための最良の方法ではありません。

関数型プログラミングを実際に学ぶには、Lispとその方言(ClojureScheme)、ErlangHaskellなどの著名な関数型プログラミング言語の1つが最適です。これらのいずれも、関数型プログラミングの考え方で機能する完璧なツールです。 F#は、.Netのバックグラウンドがある場合にも適していますが、厳密には関数型プログラミング言語ではなく、マルチパラダイム言語です。


tdammersのコメントでの注意事項:

実際、LISP、clojure、schemeもマルチパラダイムです。Haskellは、純粋でデフォルトの遅延でありながら、モナディックコンテキストで命令型プログラミングを可能にし、並行処理を幅広くサポートしています。これらはすべて、カプセル化、継承、単一の責任、構成など、OOPの世界で収集された知恵の大部分を実装するメカニズムを備えています。言語が他のパラダイムを許可するかどうかはそれほど重要ではありません。それは、どのパラダイムが言語の出発​​点を形成するかについてです。

彼らは他のパラダイムを超える関数型プログラミングを奨励するため、Lispとその方言とErlangのは、F#のより良い候補である私の知る限りでは、何tdammersは美しくとして述べ言語の開始点。F#には関数型プログラミングが含まれますが、他のサポートされているパラダイムである命令型プログラミングとooプログラミングよりも推奨されません。


最後の文について:その場合、F#は、機能的な考え方にとらわれないため、より良い候補であると私は主張します。マルチパラダイム言語では、ねじをハンマーで打ち始めると、ドライバーに切り替えるだけです。単一のパラダイムに閉じ込められると、ネジと釘の違いを見逃す可能性があります。
R.マルティーニョフェルナンデス

問題は、プログラミングではなく、関数型プログラミングを学ぶ方法です。私は、opがマルチパラダイム言語での経験があり、関数型プログラミングを学ぶ最も効率的な方法を望んでいると想定しています。この場合、F#は良い候補ですが、完全なものではありません。単一のパラダイムに閉じ込められることは、それ以外のすべてに対処する必要がないので、その単一のパラダイムについて学びたいときに明らかに最良の方法です。
yannis

私は、パラダイムが適切である場合、および特定のタスクに不適切である場合の学習は、学習の一部であり、おそらく最も重要であると考えています。
R.マルティーニョフェルナンデス

4
実際、LISP、clojure、schemeもマルチパラダイムです。Haskellは、純粋でデフォルトの遅延でありながら、モナディックコンテキストで命令型プログラミングを可能にし、並行処理を幅広くサポートしています。これらはすべて、カプセル化、継承、単一の責任、構成など、OOPの世界で収集された知恵の大部分を実装するメカニズムを備えています。言語が他のパラダイムを許可するかどうかはそれほど重要ではありません。それは、どのパラダイムが言語の出発​​点を形成するかについてです。
tdammers '29年

2
@MartinhoFernandesは:一つは、一つのパラダイムであるトラップされると主張している可能性があり、完璧な、それは:-)お尻の痛みが本当にあるときに学習する方法を
イェルクWミッターク

2

Cで関数型プログラミングのすべての側面を学ぶことはできません。しかし、確実に関数型プログラミングをあらゆる命令型言語から始めることができます。これらの開始ビットは、「プログラミング中に物事を純粋に保つ方法」です。そして、それはまたCを行うことができます。詳細については、このブログ投稿を確認してください-

http://www.johndcook.com/blog/2011/07/24/get-started-functional-programming/


2

TL; DR

関数型プログラミングは、クロージャーとそのアプリケーションに関するものです。誰かがCの降下クロージャーライブラリを表示できる場合を除き、Cを使用して関数型プログラミングを学ぶことを忘れてください。

関数型プログラミングとは何ですか?

関数型プログラミングの基本的な概念は、大まかに言えば、変数バインディングとともに関数をキャプチャするクロージャの概念です。クロージャーの普及に加えて、関数型プログラミングには、再帰的な関数や不変の値の使用(どちらもうまく機能する)など、他にもいくつかの特徴があります。これらの特性は何よりも文化的な問題であり、事実上すべての言語でそれらを使用するための技術的な障害はありません。これが、私の答えでクロージャに焦点を当てている理由です。すべての言語で簡単にクロージャを作成できるわけではありません。

クロージャの有用性の3つのイラスト

クロージャの典型的な用途は、プライバシーメカニズムの実装です。たとえば、Javascriptコード–例ではJavascriptを選択しました。これは、いわゆる「Cのような構文」を持つ関数型言語であり、あなたの質問はCに精通していることを示唆しているためです。

create_counter = function()
{
  var x = 0;
  var counter = function()
  {
    ++x;
    return x;
  };
  return counter;
}

次に

a = create_counter();
b = create_counter();

2つの関数がaあり、b互いに素なコレクションを数えます。この例の要点は、変数xは、クロージャーを定義するcounterクロージャーによってキャプチャされ、そのたびに新しいcounterクロージャーis instantiated by the function, it gets its fresh own idea of whatx`がキャプチャされるということです。

クロージャのもう1つの一般的な使用法は、関数の部分的なアプリケーションの定義です。syslog関数の実装と同様のレポート機能があるとします。

var log = function(priority, message) {

};

どこの引数prioritymessage文字列の一つである第1の一つとして期待されている"debug""info"と上のようにします。次のようにログファクトリを定義できます。

var logWithPriority = function(priority) {
  return function(message) {
    log(priority, message);
  };
};

それを使用して、ログ機能の特殊なバージョンを定義します。

var debug = logWithPriority("debug");
var info = logWithPriority("info");

このforようにエラーが発生しやすいループを作成する代わりに、これは非常に便利です。

for(i = 0; i < journal.length; ++i) {
   log("info", journal[i]);
}

より簡潔で、より短く、よりシンプルに記述できます(はありませんがiはるかに優れてます)。

journal.forEach(logWithPriority("info"));

クロージャの3番目の重要なアプリケーション分野は遅延評価の実装です。特別な言語サポートがより良い実装を提供できることに注意してください。

遅延関数は、直接計算を実行する代わりに、質問を実行するために呼び出す(または遅延の専門用語で「強制する」)ことができるクロージャーを返します。これを行う動機は、計算の準備と計算の実行を分離することです。これの実用的な例は、正規表現のコンパイルです。プログラムが起動時に多くの正規表現をコンパイルする場合、起動するのに多くの時間が必要になります。代わりに、正規表現を遅延コンパイルして、必要に応じて強制的に実行すると、プログラムをすぐに開始できます。もちろん、正規表現は、かなりの初期化時間を必要とする任意の構造で置き換えることができます。

クロージャを使用して遅延評価を実装する方法を次に示します。配列の最大値を返すarrayMax関数の従来の実装を考えてます。

function arrayMax(array) {
  return array.reduce(function(a, b) {
    return Math.min(a, b);
  };
}

レイジーバリアントは次のようになります。

function arrayMax(array) {
  var memo = null;
  function actuallyCompute() {
    if(memo === null) {
      memo = array.reduce(function(a, b) {
        return Math.min(a, b);
      });
    }
    return memo;
  }
  return actuallyCompute;
}

戻り値は、値を計算したり、すでに計算されている場合はもう一度取得したりするために使用できるクロージャーです。

これらの3つの例で、クロージャーとそのアプリケーションが関数型プログラミングの中核であることを確信できます。

結論

関数型プログラミングを学ぶとは、クロージャーを使ってプログラミングする方法を学ぶことです。結果として、関数型プログラミングを研究するための言語を探すときは、クロージャを簡単に操作できる言語、特に関数の部分的な適用を検討する必要があります。逆に、クロージャを簡単に操作できない言語は、適切な選択ではありません。


1
この素晴らしいサンプルをありがとう。ところで、var infoを定義すると、journal.forEach(info)にならないでしょうか?
ejaenv

はい、それは適切な変形です!:)
Michael Le BarbierGrünewald15年

1

使用するツールは学習に大きな影響を与えると思います。使用するプログラミング言語が利用する手段を提供していないプログラミング概念を学ぶことはほとんど不可能です。もちろん、常にいくつかのことを学ぶことはできますが、適切に学ぶことはできません。

ので、しかし、それは、学術とにかくあるマルティーニが彼のコメントで述べている、あなたがしても可能性が関数型プログラミングを学ぶ、あなたがすべきことをやろうではない、これはある言語があるので、非常に簡単には。


1

Cで関数型プログラミングを学ぶべきではありませんが、厳密な関数型言語(Haskell、Caml、Erlangなど)で学びます。

関数型の初心者であれば、非関数型言語を使ってそれを実現することはできません。より可能性が高いのは、関数型プログラミングだと思うことをするように訓練し、間違った方法で物事を学ぶことです。また、物事を正しい方法で「再学習」することは、最初に正しい方法で学ぶよりも常に困難です。

とにかく、Cで汎関数を実行することは、すでに汎関数を知っている人にとっては良い練習だと思います。なぜなら、その人は裏で何が起こっているのか、コンピューターが実際に何をしているかを知るからです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.