質問

大学の 2 年目に、私たちは Haskell を「教えられました」が、私はそれについてほとんど何も知りませんし、関数型プログラミングについてもさらに知りませんでした。

関数型プログラミングとは何ですか。非関数型プログラミングの代わりに関数型プログラミングを使用する理由や場所は何ですか。C は非関数型プログラミング言語であると考えるのは正しいですか?

役に立ちましたか?

解決

関数型言語の重要な機能の 1 つは、ファーストクラス関数の概念です。その考え方は、関数をパラメーターとして他の関数に渡し、それらを値として返すことができるということです。

関数型プログラミングには、状態を変更しないコードを記述することが含まれます。そうする主な理由は、関数を連続して呼び出しても同じ結果が得られるようにするためです。関数コードは、ファーストクラス関数をサポートする任意の言語で作成できますが、Haskell など、状態を変更できない言語もあります。実際、副作用 (テキストの出力など) をまったく行うべきではありません。まったく役に立たないように思えます。

Haskell は代わりに、IO に対して別のアプローチを採用しています。モナド。これらは、インタープリタのトップレベルによって実行される必要な IO 操作を含むオブジェクトです。他のレベルでは、それらはシステム内の単なるオブジェクトです。

関数型プログラミングにはどのような利点がありますか?関数型プログラミングでは、各コンポーネントが完全に分離されているため、バグの可能性が少ないコーディングが可能になります。また、再帰関数とファーストクラス関数を使用すると、通常はコードの構造を反映した単純な正しさの証明が可能になります。

他のヒント

関数型プログラミングとは

現在一般的に使用されている「関数型プログラミング」には 2 つの異なる定義があります。

(Lisp に由来する) 古い定義では、関数型プログラミングとは、第一級の関数を使用したプログラミングに関するものです。ここで、関数は他の値と同様に扱われるため、関数を引数として他の関数に渡したり、関数が戻り値の中で関数を返すことができます。これは最終的に次のような高次関数の使用になります。 map そして reduce (聞いたことがあるかもしれません mapReduce これは Google によって頻繁に使用される 1 つの操作であり、当然のことながら、これは近い親戚です!)。.NET のタイプ System.Func そして System.Action 高階関数を C# で利用できるようにします。C# ではカリー化は現実的ではありませんが、他の関数を引数として受け入れる関数は一般的です。の Parallel.For 関数。

(Haskell によって普及した) 若い定義では、関数型プログラミングは、突然変異を含む副作用を最小限に抑え、制御することも目的としています。式を構成して問題を解決するプログラムを作成します。これは、より一般的には「純粋関数型プログラミング」と呼ばれます。これは、「純粋関数型データ構造」と呼ばれるデータ構造に対する大きく異なるアプローチによって可能になります。1 つの問題は、従来の命令型アルゴリズムを純粋に機能的なデータ構造を使用するように変換すると、通常、パフォーマンスが 10 倍悪化することです。Haskell は現存する唯一の純粋関数型プログラミング言語ですが、その概念は次のようなライブラリによって主流のプログラミングに浸透しています。 Linq ネット上。

非関数型プログラミングの代わりにそれを使用したい場所はどこですか?

どこにでも。C# のラムダには大きな利点があることが実証されました。C++11にはラムダがあります。今では高階関数を使用しない理由はありません。F# のような言語を使用できる場合は、型推論、自動一般化、カリー化、部分適用 (および他の多くの言語機能) の恩恵を受けることもできます。

C は非関数型プログラミング言語であると考えるのは正しいですか?

はい。C は手続き型言語です。ただし、関数ポインターと関数を使用すると、関数型プログラミングの利点の一部を得ることができます。 void * Cで。

この記事をチェックしてみる価値があるかもしれません F#「101」 最近CoDe Magに投稿されました。

また、 ダスティン・キャンベルの素晴らしいブログ ここには、F# を使いこなすための冒険に関する多くの記事が投稿されています。

これらがお役に立てば幸いです:)

編集:

また、付け加えておきますが、関数型プログラミングについての私の理解は次のとおりです。 すべて インスタンス/ステートフル オブジェクトではなく、関数または関数のパラメーターです。しかし、私は間違っている可能性があります。F# はぜひ始めたいのですが、時間がありません。:)

John the Statistician のサンプル コードには関数型プログラミングは示されていません。関数型プログラミングを行う場合、重要なのはコードが割り当てを行わないことだからです ( record = thingConstructor(t) は割り当てです)、副作用はありません (localMap.put(record) は副作用のあるステートメントです)。これら 2 つの制約の結果、 関数 dos は、引数と戻り値によって完全にキャプチャされます。C++ を使用して関数型言語をエミュレートしたい場合は、Statistician のコードを次のように書き換えます。

RT getOrCreate(const T thing, 
                  const Function<RT<T>> thingConstructor, 
                  const Map<T,RT<T>> localMap) {
    return localMap.contains(t) ?
        localMap.get(t) :
        localMap.put(t,thingConstructor(t));
}

副作用なしルールの結果、すべてのステートメントは戻り値の一部になります (したがって、 return 来る 初め)、すべてのステートメントは式です。関数型プログラミングを強制する言語では、 return キーワードが暗黙的に含まれており、 もし ステートメントは C++ のように動作します ?: オペレーター。

また、すべては不変なので、 localMap.put の新しいコピーを作成する必要があります ローカルマップ 元のファイルを変更する代わりにそれを返します ローカルマップ, 、通常の C++ または Java プログラムと同じです。localMap の構造によっては、コピーでオリジナルへのポインターが再利用され、コピーする必要があるデータの量が削減される場合があります。

関数型プログラミングの利点としては、関数型プログラムが短く、関数型プログラムの変更が容易であること (考慮すべき隠れたグローバル効果がないため)、プログラムを正しく実行するのが容易であることが挙げられます。最初の場所。

ただし、関数型プログラムは (実行する必要があるすべてのコピーのため) 実行が遅くなる傾向があり、メモリ アドレス、リトル エンディアンを処理する他のプログラム、オペレーティング システム プロセス、またはオペレーティング システムとうまく対話できない傾向があります。バイトのブロック、およびその他のマシン固有の機能しないビット。非相互運用性の程度は、機能の純度および型システムの厳密さと逆相関する傾向があります。

より一般的な関数型言語には、非常に厳密な型システムがあります。OCAML では、整数と浮動小数点演算を混合したり、同じ演算子を使用したりすることさえできません (+ は整数の加算、+.フロートを追加するためのものです)。これは、特定の種類のバグを検出する型チェッカーの機能をどの程度高く評価するかによって、利点にも欠点にもなりえます。

関数型言語は、非常に大規模なランタイム環境を持つ傾向があります。Haskell は例外です (GHC 実行可能ファイルは、コンパイル時と実行時の両方で C プログラムとほぼ同じくらい小さいです) が、SML、Common Lisp、および Scheme プログラムは常に大量のメモリを必要とします。

はい、C は非関数型言語であるという考えは正しいです。C は手続き型言語です。

私は関数型プログラミングを使用して、より抽象的なバージョンを作成して代わりに使用することで、繰り返しの作業を節約することを好みます。例を挙げてみましょう。Java では、構造を記録するためのマップを作成し、getOrCreate 構造を作成することがよくあります。

SomeKindOfRecord<T> getOrCreate(T thing) { 
    if(localMap.contains(t)) { return localMap.get(t); }
    SomeKindOfRecord<T> record = new SomeKindOfRecord<T>(t);
    localMap = localMap.put(t,record);
    return record; 
}

これは非常に頻繁に起こります。さて、関数型言語で書くと、

RT<T> getOrCreate(T thing, 
                  Function<RT<T>> thingConstructor, 
                  Map<T,RT<T>> localMap) {
    if(localMap.contains(t)) { return localMap.get(t); }
    RT<T> record = thingConstructor(t);
    localMap = localMap.put(t,record);
    return record; 
}

そして、これらの新しいものを再び書く必要はなくなり、それを継承することができます。しかし、このことのコンストラクターでは、継承するよりももっと良いことを行うことができます。

getOrCreate = myLib.getOrCreate(*,
                                SomeKindOfRecord<T>.constructor(<T>), 
                                localMap);

(* は「このパラメータを開いたままにする」表記の一種であり、一種のカリー化です)

そして、ローカルの getOrCreate は、継承の依存関係を持たずに、すべてを 1 行で記述した場合とまったく同じになります。

F# に関する優れたテキストを探している場合

エキスパート F# ドン・サイムとの共著です。F#の作者。彼は、F# を作成できるように、特に .NET のジェネリックスに取り組みました。

F# は OCaml をモデルにしているため、OCaml のテキストは F# の学習にも役立ちます。

見つけました 関数型プログラミングとは何ですか? 役立つように

機能プログラミングとは、純粋な機能を作成すること、隠された入力と出力をできる限り削除することです。そのため、できるだけ多くのコードが入力と出力の関係を説明します。

明示的なものを好む when パラメータ

public Program getProgramAt(TVGuide guide, int channel, Date when) {
  Schedule schedule = guide.getSchedule(channel);

  Program program = schedule.programAt(when);

  return program;
}

以上

public Program getCurrentProgram(TVGuide guide, int channel) {
  Schedule schedule = guide.getSchedule(channel);

  Program current = schedule.programAt(new Date());

  return current;
}

関数型言語は副作用に対して積極的に敵意を持っています。副作用は複雑さであり、複雑さはバグであり、バグは悪魔です。関数型言語は、副作用に対しても敵対的になるのに役立ちます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top