関数型プログラムがコンパイルの成功と正確さの間に相関関係があるのはなぜですか?


12

私がLINQを使い始めて以来、私は4年前から関数型プログラミングの傾向にあります。最近、私はいくつかの純粋な関数型C#コードを書いて、関数型プログラムについて読んでいることに最初に気付きました。

私はこれがなぜそうなのかを試してみましたが、成功していません。

OOプリンシパルの適用では、機能プログラムにはない「抽象化層」があり、この抽象化層により、実装が間違っていてもオブジェクト間のコントラクトを正しくすることができます。

誰かがこれを考えて、コンパイルの成功と関数型プログラミングのプログラムの正確性との相関関係の根本的な抽象的な理由を思い付きましたか?


9
Lispは関数型言語ですが、いまだにコンパイル時のチェックはありません。他のいくつかの関数型言語でも同じです。あなたが話す言語のより正確な特性評価は次のとおりです。

1
@delnan Lispは関数型プログラミング言語であるとは言いませんが、関数型プログラミングコードを書くために使用できます。Lisp方言であるClojureは関数型プログラミング言語です
sakisk 14年

2
@delnanに同意します。このステートメントは、静的に型付けされた関数型プログラミング言語、特にHindley-Milnerシステムを使用するHaskellに関連しています。主なアイデアは、型を正しく取得すれば、プログラムが正しいという自信が高まるということだと思います。
サヤスク14年

1
機能的なコードは、典型的な主流のOOPコードと同じ数の抽象化と間接化を持つことができます(それ以上ではない場合)。悪魔は細部にこだわっています-副作用が少なく、nullがないことは、追跡する目に見えない状態が少なくなり、失敗する可能性が少なくなることを意味します。これらの同じ原則を主流の命令型言語に適用できることに注意してください。これは、より多くの作業であり、多くの場合より冗長です(たとえばfinal、すべてを平手打ちする必要があります)。
ドーバル14年

1
プログラムのない完全な答えが、タイピングがあるプログラムの形式検証の粗製の形。一般に、オブジェクト指向プログラムは、置換を考慮に入れる必要があるため、複雑または非常に単純な型システムを持っています。ほとんどの場合、それらは便宜上便宜上不正確にされています。MLのようなシステムであるOTOHは、CHを最大限に使用できるので、型だけで証明をエンコードし、証明チェッカーとしてコンパイラを使用できます。
マチェイピエチョトカ14年

回答:


12

私はこの答えを物事をたくさん証明する人として書くことができるので、私にとって正しさは単に機能するものではなく、機能し、証明するのが簡単なものです。

多くの意味で、関数型プログラミングは命令型プログラミングよりも制限的です。結局のところ、Cの変数を変更しないことを妨げるものは何もありません!実際、FP言語のほとんどの機能は、ごく少数のコア機能に関して簡単に説明できます。それはすべて、ラムダ、関数の適用、およびパターンマッチングに非常に要約されます!

ただし、事前にパイパーに支払いを済ませているため、対処する必要がはるかに少なく、問題が発生する可能性のある選択肢がはるかに少なくなっています。1984年のファンなら、自由は確かに奴隷です!プログラムに101種類の巧妙なトリックを使用することにより、これらの101のいずれかが発生する可能性があるかのように、物事について推論する必要があります。それが判明したので、それは本当に難しいです:)

剣ではなく安全はさみから始めると、走るのはそれほど危険ではありません。

ここで、あなたの質問を見てみましょう。このすべてが「コンパイルして動作します!」にどのように適合するのでしょうか。現象。これの大部分は、コードを証明するのが簡単な理由と同じ理由だと思います!結局のところ、ソフトウェアを書くとき、それが正しいという非公式の証拠を構築していることになります。このため、あなたの自然なハンドウェイプルーフでカバーされているものと、コンパイラー自身の正確さ(型チェック)の概念は非常にたくさんあります。

機能とそれらの間の複雑な相互作用を追加すると、型システムによってチェックされないものが増えます。ただし、非公式の証明を作成する能力は向上しないようです。これは、最初の検査をすり抜けて、後でキャッチする必要があるものがさらにあることを意味します。


1
Iあなたの答えのように私はそれはOPの質問に答える方法が表示されない
sakisk

1
@faifは私の答えを拡大しました。TLDR:誰もが数学者です。
ダニエル・グラッツァー14年

「プログラムに101種類のきちんとしたトリックを使用することにより、これらの101のいずれかが起こる可能性があるかのように、物事について推論する必要があります!」:あなたの頭の中の多くの情報。
ジョルジオ14

12

関数型プログラミングにおけるコンパイルの成功とプログラムの正確性との相関関係の根本的な抽象的な理由は?

可変状態。

コンパイラは物事を静的にチェックします。それらはあなたのプログラムが整形式であることを保証し、型システムは正しい種類の値が正しい種類の場所で許可されることを保証しようとするメカニズムを提供します。型システムはまた、正しい種類のセマンティクスが正しい種類の場所で許可されることを保証しようとします。

プログラムが状態を導入するとすぐに、後者の制約はあまり役に立たなくなります。適切な場所の適切な値を心配する必要があるだけでなく、プログラムの任意のポイントでその値が変化することを考慮する必要もあります。その状態と共に変化するコードのセマンティクスを考慮する必要があります。

関数型プログラミングをうまくやっていれば、可変状態はありません(またはほとんどありません)。

ここで原因についていくつかの議論があります-コンパイラがより多くのバグをキャッチできるために状態のないプログラムがコンパイル後により頻繁に動作する場合、またはそのプログラミングスタイルがより少ないバグを生成するためにコンパイル後に状態のないプログラムがより頻繁に動作する場合

私の経験ではおそらく両方の組み合わせです。


2
「これは私の経験ではおそらく両方の組み合わせです。」:私は同じ経験を持っています。静的型付けは、命令型言語(Pascalなど)を使用している場合にも、コンパイル時にエラーをキャッチします。FPでは、可変性の回避、さらに宣言的なプログラミングスタイルの使用により、コードについての推論が容易になります。言語が両方を提供する場合、両方の利点が得られます。
ジョルジオ14年

7

簡単に言えば、制限は物事をまとめる正しい方法が少ないことを意味し、一流の関数はループ構造のようなものを簡単に除外することを可能にします。この答えからループを取ります、例えば:

for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
    String string = iterator.next();
    if (string.isEmpty()) {
        iterator.remove();
    }
}

これは、たまたまコレクションを繰り返し処理している間にコレクションから要素を削除するためのJavaでの安全な必須の方法の1つです。非常によく似ているが間違っている方法がたくさんあります。この方法を知らない人は、代わりにコピーを繰り返すなど、複雑な方法で問題を回避することがあります。

このジェネリックを作成するのはそれほど難しくないのでStrings、のコレクション以上で機能しますが、ファーストクラスの関数がなければ、述語(内の条件if)を置き換えることができないため、このコードはコピーして貼り付けられる傾向がありますわずかに修正されました。

あなたを与えるファーストクラスの機能を組み合わせる能力あなたがいない場合、それは非常に迷惑になり不変性の制約で、パラメータとして述語を渡すことを、あなたはのような単純なビルディング・ブロックを思い付くfilterこのScalaのコードのように、それは同じことをします:

list filter (!_.isEmpty)

次に、Scalaの場合、コンパイル時に型システムが何をチェックするかを考えますが、これらのチェックは、最初に実行したときに動的型システムによっても行われます。

  • listfilterメソッドをサポートする何らかの種類、つまりコレクションである必要があります。
  • の要素には、ブール値を返すメソッドがlist必要isEmptyです。
  • 出力は、同じタイプの要素を持つ(潜在的に)より小さなコレクションになります。

これらのことを確認したら、プログラマーが台無しにする他の方法は何ですか?を誤って忘れて!しまい、非常に明白なテストケースエラーが発生しました。それが犯すことのできる唯一の間違いであり、逆条件をテストしたコードから直接翻訳していたので、私はそれを犯しました。

このパターンは何度も繰り返されます。ファーストクラスの関数を使用すると、正確なセマンティクスを備えた小さな再利用可能なユーティリティに物事をリファクタリングできます。不変性などの制限により、そうするための推進力が得られます。

もちろん、これはすべて、プログラマーが単純化機能がfilterすでに存在することを知り、それを見つけることができるか、自分で作成することの利点を認識することに依存しています。テール再帰のみを使用して、これをどこでも自分で実装してみてください。そうすれば、命令型バージョンと同じ複雑さのボートに戻ってしまいます。非常に簡単に記述できるからといって、単純なバージョンが明白であることを意味しません。


「これらのことを確認したら、プログラマーが台無しにする他の方法はありますか?」:これは、(1)静的型付け+(2)機能スタイルが物事を台無しにする方法をあまり残さないという私の経験を何らかの形で確認します。その結果、FPを使用するときに、正しいプログラムをより速く取得する傾向があり、作成するユニットテストを減らす必要があります。
ジョルジオ14年

2

関数型プログラミングのコンパイルと実行時の正確性の間には大きな相関関係はないと思います。静的に型付けされたコンパイルと実行時の正確性の間には、少なくとも、キャストしていない場合は正しい型がある可能性があるため、何らかの相関関係がある可能性があります。

説明したように、コンパイルの成功と実行時の型の正しさを何らかの形で相関させるプログラミング言語の側面は、静的型付けです。強く型付けされた値または場所(Javaや.Netなど)またはまったく付けられない(型情報が失われる環境、またはCやC ++などの弱い型付けの環境)。

ただし、関数型プログラミング自体は、共有データや可変状態の回避など、他の方法で役立つ場合があります。

両方の側面が正確に重要な相関関係を持っている可能性がありますが、コンパイルや実行時エラーがないことは、厳密に言えば、プログラムが本来行うことを実行して失敗するため、より広い意味での正確性について何も伝えないことに注意する必要があります無効な入力または制御不能なランタイム障害。そのためには、ビジネスルール、要件、ユースケース、アサーション、単体テスト、統合テストなどが必要です。最終的には、少なくとも私の意見では、関数プログラミング、静的型付け、またはその両方よりもはるかに信頼性が高くなります。


この。コンパイルが成功しても、プログラムの正確さを判断することはできません。コンパイラーが、プログラムの仕様に貢献したすべての人の頻繁に矛盾する不正確な要件を理解できれば、コンパイルの成功が正しいと見なされる可能性があります。しかし、その神話的なコンパイラにはプログラマは必要ありません!そこかもしれないが、わずかに高い不可欠のプログラムに対して、機能のためのコンパイルと正しさとの間の全体的な相関関係、それは私がそれは基本的に無関係だと思うことを、総正当性判断のような小さな部分です
ヨルダンリーガー

2

マネージャーの説明:

機能的なプログラムは、すべてが接続されている1つの大きなマシン、チューブ、ケーブルのようなものです。[車]

手続き型プログラムは、小さなマシンを含む部屋のある建物のようなもので、ビンに部分製品を保管し、他の場所から部分製品を入手します。[工場]

そのため、機能マシンがすでに適合している場合、何かを生成することになります。手続き型複合体が実行されると、特定の効果が監視され、カオスが導入され、機能が保証されない可能性があります。正しく統合されたすべてのチェックリストを持っている場合でも、可能性が非常に多くの状態、状況(部分的な製品が横たわっている、バケツがあふれている、不足している)があります。


しかし、真剣に、手続き型コードは、機能的なコードほど望ましい結果のセマンティクスを指定しません。手続き型プログラマーは、状況コードとデータによってより簡単に逃げることができ、1つのことを行うためのいくつかの方法を導入できます(不完全なものもあります)。通常、無関係なデータが作成されます。機能プログラマーは、問題がより複雑になると時間がかかるかもしれませんか?

強力な型指定された関数型言語は、より優れたデータおよびフロー分析を実行できます。手続き型言語では、プログラムの目標は、多くの場合、プログラムの外部で、正式な正確性分析として定義する必要があります。


1
より良いアナロジー:関数型プログラミングは、顧客のいないヘルプデスクのようなものです。すべてが素晴らしい(目的や効率に疑問がなければ)。
ブレンダン14年

@ブレンダンの自動車と工場はそのような悪い類推を形成しません。関数型言語の(小規模)プログラムが動作する可能性が高く、「工場」よりもエラーが少ない理由を説明しようとします。しかし、OOPを救うために、工場はいくつかの物を生産することができ、より大きくなると言います。あなたの比較は適切です。FPがどれくらいの頻度で並列化および最適化できるかを確認しますが、実際には(駄洒落ではない)遅い結果をもたらします。私はまだFPを保持しています。
ジョープエッゲン14年

大規模な関数型プログラミングは、en.wikipedia.org / wiki / Spherical_cowで非常にうまく機能します 。
デン14年

@Den私自身は、大規模なFPプロジェクトでの実行可能性の問題を恐れません。大好きです。汎化には制限があります。しかし、その最後の声明も一般化であるため...(球形の牛に感謝します)
ジョープ・エッゲン14年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.