関数型プログラミングの読みやすさ[終了]


13

私はこれに興味があります。関数型言語を学ぶ前に思い出したので、それらはすべて恐ろしく、ひどく、ひどく読めないと思っていました。Haskellとf#を知ったので、少ないコードを読むのに少し時間がかかりますが、その小さなコードは命令型言語での同等の量よりもはるかに多いので、純益のように感じ、私は極端ではありません機能的に実践。

ここに私の質問があります。私は、OOPの人々から、機能的なスタイルはひどく読めないと常に聞いています。これが事実であり、自分を欺いているのか、または関数型言語を習得するのに時間がかかったのであれば、スタイル全体がOOPよりも読みにくくなるのではないかと思います。

誰かが証拠を見たり、逸話を手に入れたりして、おそらくこれを言うのに十分な頻度で行っていますか?機能的に実際に書くのが読みにくい場合は、使い続けたくありませんが、そうなのかどうかはわかりません。


1
関数型プログラミングについてほとんど何も知らず、「すごい。」と考えたとき、「Super Nario Brothers」svn.coderepos.org/share/lang/haskell/narioのコードを見たことを覚えています。これは本当に読みやすいようです」
-WuHoUnited



3
@BlackICE linqとlambdaは、「関数型プログラミング」の定義とはかけ離れています。関数型プログラミングでは、オブジェクト/クラス/レコードを単なるタイプとしてではなく、タイプとして認識し始めると、多くの新しい能力とテクニックが得られるため、タイプシステムが頻繁に関係します。LINQ式とLambda式(またはリストモナド関数と高階関数)は、2つの特定の結果として得られる手法にすぎず、さらに多くの手法があります。
ジミーホファ

回答:


15

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

割り当てはx = x + 1、数学者にとっては奇妙に聞こえますが、それは割り当てが比較と誤解を招くように見えるためです。

単純なOOP設計パターンは、これらのパターンに精通していない人にとっては完全に不明瞭です。シングルトンを検討してください。誰かが求めるだろう「なぜ私は神秘的な方法は何ですか?プライベートコンストラクタが必要なのか getInstance() 、我々はグローバル変数を作成し、そこにオブジェクトを割り当てていないのはなぜ?」

FPコードにもまったく同じことが当てはまります。背後の論理パターンを知らない限り、非常に基本的なこと、たとえば関数を別の関数の引数として渡す方法などを理解することさえ非常に困難です。

これを言って、FPは特効薬ではないことを理解する必要があります。FPを適用するのが難しいと思われる多くのアプリケーションがあります。そのため、コードが読みにくくなります。


人々は自分自身に似たものを作成する必要があります(人間性)。たとえば、コンピュータービジョンでも、ニューラルネットがあります。人体はオブジェクト、属性、メソッドで構成されており、オブジェクト、属性、メソッドを使用して他のことを記述します。だから、関数型プログラミングはどんな意味がありません
user25

12

短い答え:

関数型プログラミングコードは読みにくいと人々に言わせる要素の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#を含む)でよりコンパクトであり、平易な英語の単語よりも記号を優先します。

これは、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を使ったことがなく、彼らの公式チュートリアルがダウンしているので、例を挙げることはできません。誰かが例を持っているなら、私の答えを修正してください。

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


8
私は感情に同意しますが、異なる理由があります。それはだない専門家ができる方法を簡単について書くコードは、一般的にはるかに多くの場合、それが書かれているよりも、読まれるよう、コードを。短いコードが可能また、ヘルプ可読性は、貴重な時間、画面のスペース、および精神的な能力を無駄にしないことによって、何かがすでに短い指標から明らかである場合(例えば、代わりにセミコロンの改行、2つの偶然とにかく)。それがなったときに、それはまた傷つけることができる、あまりにも不可解な(例えば、私が好むfor x in xs以上for x xs、それは私がループ変数とコンテナを区別するのに役立ちますので、)。

私が見つけた人の多くは、あなたが言ったようにあなたがリストしたC#スニペットにも文句を言います、それはまたFPの例です。ほとんどのOOPの人々がスニペットを読むことができる場合、これは読みやすさよりも私の同僚の問題かもしれません。
ジミーホッファ

@Jimmy Hoffa:プログラマーをご覧ください。stackexchange.com/ a / 158721/6605では、C#スニペットを正確に説明し、初心者プログラマーがそれをどのように認識しているかを説明しています。
アルセニムルゼンコ

1
@Sergiy:JavaまたはC#では、メソッドシグネチャにはmethodキーワードがありません。例:public int ComputePrice(Product product)。PHPが行ったように、このようなキーワードを追加すると、読みやすくなるのではなく、混乱が生じます。プログラマーが関数がその署名からの関数であることを理解できない場合、このプログラマーはまったく経験がないか、これまで見た最悪のコードよりもコードがはるかに読みにくくなります。
Arseni Mourzenko

1
@Sergiy:冗長性が役立つ場合があります(そうでない場合は、などの言語とコードが表示されますp i ComputePrice(product): _.unitPrice * ~.cart[_])が、一部の言語はそれを行き過ぎています。functionPHP の冗長キーワードの例が良い例です。
アルセニムルゼンコ14年

6

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

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

だから、OOPの人々のチームであっても、関数やクロージャーでコレクションをマッピングするなど、理解や学習が容易な概念を使用している限り、関数型プログラミングを少し使用するのは合理的だと思います

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


2

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

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

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


1

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

型推論は扱いにくい機能です。通常、これは開発の優れた加速器ですが、コンテキストが不足しているために混乱を招くエラーが発生するため、どのタイプが関係しているかを把握するのが難しい場合があります。これは関数型プログラミング言語に限定されません-私はC ++テンプレートでも見ました!

現代の言語はマルチパラダイムになる傾向があります。これには、C#とF#の両方が含まれます。C#で関数型スタイルを記述し、F#で命令型スタイルを記述することができます。関数型言語を批判する同じ人々は、おそらくオブジェクト指向言語で関数型コードを書いています。

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

  1. リファクタリングではなく言語を学習するときにスタイルを変更すると、一貫性が失われます。
  2. 1つのファイルに多すぎます。
  3. 1行のステートメントが多すぎます。

ミスに関しては、以下も追加します。4.シンボルの過剰使用。例:〜@#$%^&*()-_ + = \ | /。、; 5.暗黙的な機能:オプションの宣言/キーワード/ステートメント、暗黙的な変換など。
セルギーソコレンコ14年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.