web-dev-qa-db-ja.com

関数型プログラミングの読みやすさ

関数型言語を学ぶ前に思い出すので、私はこれに興味があります。それらはすべてひどく、ひどく、ひどく読めないものだと思っていました。 Haskellとf#を知ったので、少ないコードを読み取るには少し時間がかかることがわかりますが、その小さなコードは命令型言語で同等の量をはるかに超えるため、純益のように感じ、私は極端ではありませんファンクショナルで実践。

これが私の質問です。OOP機能的なスタイルはひどく読めないという話をよく聞きます。これが事実であり、自分自身を騙しているのか、または彼らが学ぶのに時間をかけたのか、興味があります。関数型言語の場合、スタイル全体がOOPより読みにくくなることはありませんか?

誰かが何らかの証拠を見たり、これが多分言ったりするのに十分な頻度でこれが何らかの方法で進んだのを見た逸話を手に入れましたか?機能的に書くことが可読性が低い場合、それを使い続けたくありませんが、そうであるかどうかは本当にわかりません。

13
Jimmy Hoffa

コードの可読性は非常に主観的です。このため、同じコードを読み取り可能または読み取り不可能と見なす人が異なります。

割り当て、_x = x + 1_は、数学者には奇妙に聞こえます。

単純なOOPデザインパターンは、これらのパターンに慣れていない人にとっては完全に不明瞭です。singletonを検討してください。誰かが尋ねるでしょう 「なぜプライベートコンストラクタが必要なのですか?謎のメソッドとは何ですかgetInstance()?グローバル変数を作成して、そこにオブジェクトを割り当てますか?」

非常に同じことがFPコードに適用されます。舞台裏で論理パターンを知らない限り、非常に基本的なものを理解することさえ非常に困難です。たとえば、関数を引数として別の関数に渡します。

FPは特効薬ではないことを理解する必要があります。FPを適用するのが難しいため、これにより、コードが読みにくくなります

15
bytebuster

短い答え:

関数型プログラミングコードは読みにくいと人々に言わせる要素の1つは、よりコンパクトな構文を優先することです。

長い答え:

関数型プログラミング自体は、パラダイムであり、コードを記述するスタイルではないため、読み取り可能または読み取り不可能にすることはできません。たとえばC#では、関数型プログラミングは次のようになります。

_return this.Data.Products
    .Where(c => c.IsEnabled)
    .GroupBy(c => c.Category)
    .Select(c => new PricesPerCategory(category: c.Key, minimum: c.Min(d => d.Price), maximum: c.Max(d => d.Price)));
_

また、Java、C#、または同様の言語で十分な経験がある人なら誰でも読むことができると考えられます。

一方、言語構文は、一般的なOOP=言語に比べて、多くの関数型言語(HaskellやF#を含む)の方がコンパクトで、英語ではなくWordよりも記号を優先します。

これはFP=以外の言語にも適用されます。人気のあるOOP言語を、より多くの英語の単語を使用する傾向があるいくつかのあまり人気のない言語と比較すると、最後の言語はプログラミングの経験がない人でも理解しやすくなります。

比較:

_public void IsWithinRanges<T>(T number, param Range<T>[] ranges) where T : INumeric
{
    foreach (var range in ranges)
    {
        if (number >= range.Left && number <= range.Right)
        {
            return true;
        }
    }

    return false;
}
_

に:

_public function void IsWithinRanges
    with parameters T number, param array of (Range of T) ranges
    using generic type T
    given that T implements INumeric
{
    for each (var range in ranges)
    {
        if (number is from range.Left to range.Right)
        {
            return true;
        }
    }

    return false;
}
_

同じやり方で:

_var a = ((b - c) in 1..n) ? d : 0;
_

架空の言語で次のように表現できます。

_define variable a being equal to d if (b minus c) is between 1 and n or 0 otherwise;
_

構文が短いほど良いですか?

詳しい構文は初心者には理解しやすいですが、よりコンパクトな構文は経験豊富な開発者には簡単です。コードが短いほど、入力する文字が少なくなり、生産性が向上します。

特に、構文から推測される可能性のあるものを示すためにキーワードをタイプするように人に強いることは実際には意味がありません。

例:

  • PHPでは、特定の理由なしに、すべての関数またはメソッドの前にfunctionを入力する必要があります。

  • Adaは、特に正しいIDEオートコンプリート機能がないため、開発者に多くの英語の単語を入力することを強制しました。私は最近Adaを使用しておらず、公式チュートリアルがダウンしているため、例を挙げることはできません。誰かが例を挙げている場合は、私の答えを自由に変更してください。

  • 多くのFP(およびMatlab)で使用される構文_1..n_は、_between 1, n_または_between 1 and n_またはbetween (1, n)で置き換えることができます。 betweenキーワードを使用すると、言語の構文に慣れていない人でも理解しやすくなりますが、2つのドットの方がはるかに速く入力できます。

12

その理由の1つは、関数型プログラミングがより抽象的な概念で機能する傾向があるためだと思います。これにより、概念を知って理解している人にとってはコードが短くて読みやすくなります(問題の本質を適切に表現しているため)。しかし、コードに精通していない人にとっては読みにくくなります。

たとえば、関数型プログラマの場合、MaybeモナドまたはEitherモナド内のさまざまなポイントで失敗する可能性のあるコードを書くのは自然なことです。または、Stateモナドを利用してステートフルな計算を記述します。しかし、モナドの概念を理解していない人にとって、これはすべてある種の黒い魔術のように見えます。

したがって、OOP人のチームでも、関数型プログラミングのビットを使用することは、コレクションへのマッピングのように、理解または学習しやすい概念を使用する限り、合理的だと思います関数または closures を使用します。

(そしてもちろん、それはコードの一部を書いたプログラマーにも依存します。どの言語でもひどく読めないコードを書くことができ、また素敵でクリーンなスタイルで書くことができます。)

6
Petr Pudlák

読みやすさは、パラダイム、モデルなどとは関係ありません。問題ドメインのセマンティクスを反映するコードが多いほど、そのような問題ドメインの用語とイディオムを操作するコードが多くなるほど、読みやすくなります。

これがOOPコードがまったく読めない理由です。実際の問題の多くは階層的な分類法で自然に表現されるわけではありません。互いにメッセージを渡すオブジェクトは奇妙な概念であり、驚くべきことに、機能的なイディオムに自然にマッピングできる現実世界の概念がはるかに多くあります。問題は宣言的に定義される傾向があるため、宣言的な解決策がより自然です。

ただし、純粋な機能、純粋なOOP、純粋なデータフロー、または純粋なものよりも現実世界に近い可能性のあるセマンティクスは他にもたくさんあります。この事実により、問題解決のための言語指向のアプローチは、最も読みやすいコードを生成し、既存の「純粋な」パラダイムをすべて打ち破ります。ドメイン固有の言語では、すべての問題が独自の自然用語で表現されます。そして、関数型言語は、DSLの実装を容易にする点でOOP主流のものよりも少し優れています(ただし、はるかに優れたアプローチが利用可能です)。

2
SK-logic

コードの可読性は主観的です。理解不足で批判する人もいると思います。一般的なパターンの実装方法には、当然異なるイディオムがあります。たとえば、 Visitorパターンは、パターンマッチングを使用する言語では実際には意味がありません

型推論はトリッキーな機能になる可能性があります。通常、これは開発の優れたアクセラレータですが、混乱を招くエラーの原因となるコンテキストがないため、どのタイプが関係しているのかを理解するのが難しい場合があります。これは、どの関数型プログラミング言語にも限定されません。C++テンプレートでも見たことがあります。

最近の言語は multi-paradigm になる傾向があります。これには、C#とF#の両方が含まれます。 C#で関数型スタイルを記述し、F#で命令型スタイルを記述できます。関数型言語を批判する同じ人々は、おそらく関数型コードをオブジェクト指向言語で記述します。

関数型言語での商用開発はまだ比較的未熟です。私は、どの言語でも悪い形だと考えられる多くの間違いを見てきました。といった:

  1. 言語を学習するときにスタイルを変更すると(リファクタリングではなく)、矛盾が生じます。
  2. 1つのファイルに多すぎます。
  3. 1行に多すぎるステートメント。
1
Dave Hillier