Javascriptは関数型プログラミング言語ですか


34
  • Javascriptは関数型言語ですか?私はそれがオブジェクトを持っていることを知っています&あなたもそれでOOPを行うことができますが、それは関数型言語でもあります、そのように使用できますか?
  • OOPがどのようにプログラミングの次の進化のようになったか/知っている、それは「機能プログラミング」が次の進化であることを意味します(注:これは意見のプロンプトではなく、事実に基づいた答えのプロンプトであり、このノートは投稿者よりもモデレーターの方が多い;))。
  • 私は例を通して最もよく学びます。おそらく、誰かが同じタスクをOOPの方法で実行し、それから関数型プログラミングの方法で関数型プログラミングの機能を理解して比較することができます。

「関数型プログラミング」を正直に完全に理解していない:Pしたがって、Javascriptと関数型プログラミングを比較することは完全に間違っている可能性があります。

関数型プログラミングを素人の言葉で言うと、それは単に匿名関数を使用したアブスレーションの利点ですか?

または、その方法は単純すぎますか?簡単に言うと、OOPはオブジェクトを介した抽象化の利点ですが、OOPを説明するには少し単純すぎると思います。

これは関数型プログラミングの良い例ですか?...

Javascript OOPの例:

// sum some numbers
function Number( v )
{ 
  this.val = v;
}

Number.prototype.add( /*Number*/ n2 )
{
    this.val += n2.val;
}

関数型プログラミングの例:

function forEach(array, action) 
{
   for (var i = 0; i < array.length; i++)
       action(array[i]);
}  

function add(array)
{
    var i=0;
    forEach(array, function(n)
    {
        i += n;
    });
    return i;
}

var res = add([1,9]);

「関数型プログラミング言語」の定義に依存します。広い意味では、閉じた値で関数値を構築する能力、つまり「ラムダ計算」の意味で「ラムダ」構造を持ち、Javascriptが法案に適合すると理解できます。
バジルスタリンケビッチ

2
Or is that way too simple?ええ、そうです。匿名関数は、関数型プログラミングや関数型プログラミングを支持するマルチパラダイム言語に関連付けられることもありますが、関数型言語の固有の特性ではありません。しかし、それらをλ計算の実装と
みなす

Javascriptの設計により、実装がテールコール最適化を実行できなくなります。私の本では、それだけで機能的であるとラベル付けされていません。
dan_waterworth

I know it has objects & you can do OOP with it alsoいいえ、できません。クラスとオブジェクトの区別をなくすプロトタイプベースのプログラミングです。個人的には、この基本的なレベルでは、プロトタイプベースのプログラミングに欠陥があると考えています。
RokL

Javascriptは機能的な言語ではありません。機能的な機能を備えていることは確かですが、実際にはすべての言語に基本的な機能的な機能がある古き良き命令型Cも同様です。HaskellやMLなどの純粋な関数型言語は、命令型ではなく宣言型の言語です。
ALXGTV

回答:


72

Javascriptは関数型言語ですか?私はそれがオブジェクトを持っていることを知っています&あなたもそれでOOPを行うことができますが、それは関数型言語でもあります、そのように使用できますか?

命令型プログラミングまたは手続き型プログラミングが意味する場合、人々は関数型プログラミングを言うことがあります。厳密に言えば、関数型プログラミングは次のとおりです。

コンピューターサイエンスでは、関数型プログラミングは、計算を数学関数の評価として扱い、状態および可変データを回避するプログラミングパラダイムです。状態の変化を強調する命令型プログラミングスタイルとは対照的に、関数の適用を強調します。関数型プログラミングは、1930年代に関数定義、関数アプリケーション、再帰を調査するために開発された正式なシステムであるラムダ計算に根ざしています。多くの関数型プログラミング言語は、ラムダ計算の詳細と見なすことができます。

Javascriptは広く知られておらず、関数型言語として使用されていませんが、いくつかの関数型要素があります

JavaScriptはSchemeと多くの共通点を持っています。それは動的言語です。S式を簡単にシミュレートできる柔軟なデータ型(配列)があります。そして最も重要なことは、関数はラムダです。

SchemeLispの方言であり、おそらくほとんどのプログラマーが関数型プログラミングについて議論するときに考える言語の1つです。それがためになるとオリエンテーションオブジェクト、Javascriptがオブジェクト指向言語です。しかし、そのオブジェクト指向はプロトタイプベースです:

プロトタイプベースのプログラミングは、クラスが存在しないオブジェクト指向プログラミングのスタイルであり、動作の再利用(クラスベース言語の継承として知られている)は、プロトタイプとして機能する既存のオブジェクトを複製するプロセスを介して実行されます。このモデルは、クラスレス、プロトタイプ指向、またはインスタンスベースのプログラミングとしても知られています。委任は、プロトタイプベースのプログラミングをサポートする言語機能です。

そのため、Javascriptはオブジェクト指向ですが、C ++、C#、Java、PHP(および他の多くの言語)などの言語がそうであるように、より一般的なクラスベースのモデルに従いません。そしてもちろん、これは命令型言語でもあり、前述の関数型プログラミングとの混乱を招きます。

プログラミングの次の進化のようにOOPがどのようになったか/知っている、それは「関数型プログラミング」が次の進化であることを意味します

オブジェクト指向と関数型プログラミングは、多くの異なるプログラミングパラダイムのうちの2つにすぎず、異なる概念と抽象化を備えた異なるプログラミングスタイルです。キーワードは「異なる」です。他の人よりも優れた、または他の人よりも進化した単一のパラダイムはありません。それぞれのシナリオが他のシナリオよりも優れています。あるものは他のものよりも起源がかなり古いかもしれませんが、より長い期間を提供してきたので、それらをより良くする進化の観点からです。しかし、それはあまり賢い見方ではありません。

Javascriptは、上で説明したように、他の多くの言語としても、マルチパラダイムです。これにより、命令型のプロトタイプベースのオブジェクト指向の機能的なスタイルでコードを書くことができます。構築するものに最適なものを選択するのはあなた次第です。また、いくつかの単一のパラダイム言語があります。標準的な例はJavaであり、クラスベースのオブジェクト指向プログラミング1のみを許可します。

言語とパラダイムをファッションステートメントとして扱う衝動に本当に抵抗する必要があります。ほとんどがファンボーイ/ファンガールまたはマーケティング担当者によって書かれ、プログラミングの知識はほとんどありません。「より良い」、「より進化した」などの用語は適用されません。

私は例を通して最もよく学びます。おそらく、誰かが同じタスクをOOPの方法で実行し、それから関数型プログラミングの方法で関数型プログラミングの機能を理解して比較することができます。

それはひどい学習方法です。機能とオブジェクトの向きはまったく異なるスタイルであり、非常に単純なもの以外の例はいずれのスタイルにも適合しません。

1しかし最近、その範囲を汎用プログラミングに拡大しようと試みています。それがどのように行われるかを見てみましょう。


結論として:

  • Javascriptの学習に専念してください。Javascriptは美しく、非常に便利な言語です。誇大広告ではなく言語を学びましょう。
  • 非常に少数の異なるパラダイムで、すべて同じように便利です。好きなものを選択し、構築するものに最適なものを選択してください。
  • 関数型プログラミングを学びたい場合は、SchemeやClojureなど、より適した言語を選択してください。ただし、最初に関連する数学的概念を理解する必要があります。
  • あなたが尋ねる前にいくつかの研究を行ってください。あなたの質問のほとんどは、関連するウィキペディアの記事で回答されています。調査方法と質問方法を知ることは、プログラマーにとって非常に重要なスキルです。

5
+1すばらしい反応。プログラミング教育は構造化されているため、新しいコーダーは、パラダイムは排他的で離散的であると考えているようですが、そうではありません。機能的な概念を利用することが理にかなっている場合は、それを活用するOOPコードを記述してください。イベント駆動型プログラミングはパラダイムですが、EDPの側面はすべてのGUIおよびWebプログラムに確かに影響します。OOPのコア機能であるポリモーフィズムは、本当に一般的なプログラミングです。これらのアイデアに名前を付けると、優れたプログラミングの概念化に役立ちますが、他のアイデアを排除するために使用するべきではありません。
小次郎

元の質問とあなたの答えはJavascriptを記述しており、関数型プログラミングとの関係ですが、あなたの答えは、私が見たオブジェクト指向プログラミングと関数型プログラミングのより良い比較の1つだと思います。よくやった。
AnotherDeveloper

「それはひどい学習方法になるでしょう。」私は問題を提示し、OOPやFPスタイルを含むさまざまなパラダイムでそれを解決するこの本を読み終えました:github.com/crista/exercises-in-programming-style。私はそれから多くを学びました!
ニック

@nickこれは、パラダイムがどのように見え、どのように機能するかを説明することしかできませんが、なぜかわかりません、これはおそらく最も重要な側面です。しかし、理由を学ぶ前に、どのように学ぶかを学ぶ必要があります。
マシューブレント

8

Javascriptは関数型言語として使用できますが、実際には非常にうまく機能します。モナドを実装することは可能です。ラムダ構造などをサポートします。多くのオブジェクト指向機能もあるという点で関数型言語だけではありませんが、そのように使用できます。実際、関数型言語としてJavascriptを使用することは、Javascriptを使用する素晴らしい方法であることがわかりました。(jQueryとunderscore.jsの例)


良い&簡潔!関数型プログラミングは多くの場合、jsで何かを達成する最も簡単な方法であることに同意しました。
bunglestink

モナドよりもさらに興味深いのは、矢印を実装できるJS(cs.umd.edu/projects/PL/arrowlets)です。さて、JavaScriptで矢印が必要な理由については、未解決の問題です。しかし、それはできます。
rtperson

私は、矢印が有用かどうかを知るのに十分な矢印の理解ができないことを認めます。しかし、私はJavascriptでMonadsの本に取り組んでおり、Arrows(shop.oreilly.com/product/0636920023890.do)の章を追加することがあります
ザカリーK

6

進化は通常、漸進的な変化を意味します。OOPは手続き型プログラミングへのインクリメンタルな追加ではありません。実際、基礎となるプログラミングモデルとは完全に直交しており、どのモデルとも組み合わせることができます。関数型プログラミングは、手続き型、OOPなどに追加されるものではありません。これは、 基本的なコンピューティングの原理を表現するための代替基盤であり、実際に 最初のコンピューターが登場するずっと前に定式化された最初の基盤です。このような基本的なシステムはすべて同等である(つまり、あるシステムを別のシステムで表現できる)ことを理解することが重要です。

機能的アプローチを理解するには、最初に基本的な数学を取得する必要があります。Javascriptで関数型スタイルでコーディングすることの意味を知りたい場合は、jQueryの使用を開始してください。


2

いや

JavaScriptは何よりもまずオブジェクト指向言語です。

JavaScriptのプログラムを機能的なスタイルで作成できないというわけではありません。十分に努力すればチューリング完全言語で機能的なスタイルを採用できるからです。必要に応じて、アセンブラで関数型プログラミングを実行できます。しかし、これによってすべての言語が機能するわけではありませ。同様に、Haskell命令型、またはJavaを論理プログラミング言語と呼ぶこともできます。このアプローチをとると、用語はすぐに無意味になります。

IMOで言語を適切なパラダイムに分類する方法は、以下を考慮することです。

  • 言語コンストラクトによって有効になる主要なスタイルは何ですか(明らかにJavaScriptのOOP、関数型言語は関数と不変のデータ値を強調します)
  • 言語のコアライブラリでサポートされているパラダイム(JavaScriptのOOPを再度明確に)
  • 言語で無効化または非推奨にされている機能(関数型言語はJavaScriptの場合ではない可変変数を非推奨または禁止)
  • 言語を使用する開発者のコ​​ミュニティでどのような開発スタイルが普及していますか(再び、OOPはJavaScriptの世界で明らかに普及しています)

個人的には、多くの人が言語が「機能的」であると主張することを好むのは、それが現在流行の用語だからというだけのことです。

長年にわたってプログラミングパラダイムに関する少し長いが面白い視点が必要な場合は、ボブマーティンおじさんのビデオ「最後のプログラミング言語」を見る価値があります。私にとって、この講演からの素晴らしい洞察は、プログラミングパラダイムは、どの機能を組み込むかではなく、どの機能を奪うかによって定義されるということでした......


What is the dominant style enabled by the language constructsそれをPerlに適用してみてください...または、他のあなたのポイント、本当に:)
ヤンニス

2
Perl?良い挑戦です!それは、あなたが一緒に望むほとんどすべてのパラダイムをハックできるという意味で、ややアセンブリ言語に似ていますが、私が見た一般的な使用法(スクリプト)では、主に命令/手続き言語として使用されています。
ミケラ

まあ、おっともかなり一般的です。もちろん、当然のことです。そして、機能的でもありますが、一般ではありません。perlは単にperlであり、それを理解しようとする意味はありません:)
ヤンニス

JavaScriptは、少なくともクロージャーとファーストクラスの機能を備えているため、Javaよりも若干機能的です。ただし、JavaScriptはC#と同じように機能します。
レイノス

2

Javascriptは最初のプロトタイプであり、機能的な機能を備えています。これは、関数をファーストクラスオブジェクトとして使用することで付与されます。

これは、関数をデータとして使用できることを意味し、状態を維持する変数の必要性を減らすという奇妙な効果があります。自分がvarステートメントに手を伸ばすことに気付いた場合、または1つ以上の「if」ステートメントを使用している場合は、機能的なスタイルから外れています。

関数型のもう1つの特筆すべき特徴は、関数は評価の結果のみを返し、スコープ外の状態には副作用がないことです。

// oops, this is producing a side effect
function sideEffecter(){//theres no input...        
    window.thingy = 'foo';
    // hey, this isn't returning anything!!!
} 

関数型言語は非破壊的です-つまり、入力を変更せず、入力に基づいてまったく新しいデータを返します。このスレッドを参照してください:https : //stackoverflow.com/questions/749084/jquery-map-vs-each

関数型言語には、リスト/コレクションを処理する「map」、「fold」、「reduce」などの名前を持つ共通の多くのメソッドもあります。JSでは、他の言語とは異なり、これらを手作業で作成する必要があります- 最新のJSの実装にはこれらの一部がそのまま含まれていますが、いくつかの例についてはunderscore.jsなどのライブラリを参照してください。

心に留めておくべき重要なこと(IMO)は、JSがいくつかの機能パターンを利用できる一方で、それを実行するために必ずしも十分に装備されていないことです。

たとえば、配列を反復処理します。機能的なスタイルまたはネイティブループ構成を使用してこれを行うことができます。一般的に言えば、ループはよりパフォーマンスが高くなります。この例を見てください-サイズを増やしてループでヒットし、異なるブラウザで実行時間を記録してください(すでにこれを行っていますが、ベンチマークを失いました-ごめんなさい!):

var test = ['foo', 'bar', 'baz'], removeFunc, removeLoop;

//(semi)functional style...
// to be really functional each condition in the ternary would be another function
removeFunc = function(src, trg) {
    return src.length === 0 ? 
        src : 
            src[0] === trg ? 
                src.slice(1) : 
                    [src[0]].concat(removeFunc(src.slice(1), trg));
};

//but this is faster
removeLoop = function(src, trg){
    var len = src.length, // using variables to represent state...
        i=0, 
        result = [];        
    while(i < n){
       if(src[i] !== trg){
          result.push(src[i]);
       }
       i = i+1;
    }
}

さらに、機能的な構成を使用してかなりのサイズのループをヒットし、アドホックスタック管理の何らかの形式を利用しない場合、スタックをあふれさせる可能性があります(ただし、公平にするために、BIGリストが必要です)。 ..)。Node.js環境で作業している場合、これは明らかにより固定されたターゲットですが、各ブラウザーでバリアント最適化の混在を考慮する必要があります。

それは、Javascriptで関数構造を使用すべきではないということではありません。環境に関連する実装の制限に注意してください。

興味のあるリンクを次に示します。

優れた「Eloquent Javascript」のJavascriptでの関数型プログラミングに関する優れた章

リトルスケマー

私の友人がリトルスキームに基づいてJSライブラリを作成しました

FPの理解を深めるのに役立つSchemeの優れたチュートリアル

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