ファーストクラス機能


11

今週末、私は真剣にLispに目を向け始めました(つまり、Lispを学習しているだけで、C#のプロジェクトに戻らないことを意味します)。私は他の関数型言語(F#、Haskell、Erlang)に手を出したことがありますが、Lispから得られた魅力を感じていません。

Lispを学び続けると、なぜ非関数型言語が一流の関数をサポートしないのか疑問に思い始めました。C#などの言語はデリゲートで同様のことができ、C / C ++の関数へのポインタを使用できる範囲でできることを知っていますが、これがこれらの言語の機能にならない理由はありますか?関数をファーストクラスにすることに欠点はありますか?私にとっては、非常に便利なので、なぜ機能パラダイム以外の言語でそれを実装しないのかが分からなくなっています。

[編集]これまでの回答に感謝します。現在、多くの言語がファーストクラスの機能をサポートしていることが示されているので、言語を実装するのになぜ時間がかかるのかという質問を言い換えます。[/編集]


3
私は、C#が「類似したこと」を行えることに同意しません。私はそれがすべての意図と目的のためのファーストクラスの機能を持っていると言うだろう(その種のあなたの前提を台無しにする)。これは、関数リテラルの構文を持っている、あなたはなどの変数への機能を詰め込むことができます
ローガンCapaldo

@Logan-C#の例を含めるかどうかについて議論していましたが、このウィキペディアのエントリに基づいて決定することにしました。エントリによると、「関数の動的状態を保持するオブジェクトは手動で構築する必要があるため」真のファーストクラス関数はありません。しかし、それが誤った記述である場合、その理由を知りたいです!(結局のところ、私は学ぶためにここに来て、自分のやり方で動けなくなることはありません!)
ジェッティ

2
そのウィキペディアのエントリは古くなっています。最新のC#は適切なラムダを提供します。
SKロジック

その段落は不完全に書かれていると思います。C ++ファンクターはファーストクラスではなく、C#デリゲートでもないということですか?ファンクターの議論には同意するかもしれませんが、C#デリゲートに賛成かどうかはわかりません。また、「(ラムダリフティングを参照)」とも言います。これは、「値としての機能」ではなく、字句クロージャーをサポートするこれらの言語に関するステートメントです。どちらか一方がなくても構いません。その場合でも、C#には当てはまらず、字句クロージャーがあります。問題の一部は、「一流の関数」があいまいな用語になる可能性があることです。
ローガンカパルド

1
@Logan&SK-Logic-ご意見をお寄せいただきありがとうございます。私はまだ学んでいますが、炎上しないことはとても素晴らしいことです。コメントと回答をありがとうございます!
ジェッティ

回答:


5

C#、VB.NET、Python、JavaScript、今ではC ++ 0xでもファーストクラスの機能が提供されています。

更新:

クロージャーの実装には、ラムダリフティングが必要です。これは、元々、命令型プログラマーにとってはまったく異質な手法です。適切なファーストクラス関数(クロージャーを含む)には、ランタイムとVMからの少なくともある程度のサポートが必要です。また、古い関数型手法を命令型の世界に採用するのにも時間がかかりました。

そして、最も重要な部分-ガベージコレクションが存在しない場合、ファーストクラスの関数はほとんど使用できません。Javaと、その結果として.NETを使用して、最近になって大量プログラミングに導入されました。また、元のJavaのアプローチは、平均的なコーダーが理解しやすいように言語を単純化しすぎることでした。.NETが最初に続き、つい最近になって(私見、かなり正当化され、適切な)方向から離れました。

そのような概念はすべて、業界で消化されるのに時間がかかります。


回答に基づいて元の質問を編集しました。
ジェッティ

ファーストクラス関数!=クロージャー(そして後者にはGCが非常に必要です)。しかし、はい、それらは密接に関連しており、あなたはめったに、それらを分離することはめったにありません。

@delnanは、少なくとも何らかの形の字句クロージャー関数がないと、実行可能ではなく、構成可能でもありません。これは、ファーストクラスの関数定義に必須です。
SKロジック

いいえ。囲んでいるスコープの変数の参照を禁止することできます(または、関数の作成時に参照される変数の値をコピーします-これが閉包としてカウントされる場合はdunno)。結果は特に有用ではありませんが、関数はクロージャにならずに実行時に構築できるため、(奇妙な)ファーストクラスの関数ができます。

1
@ SK-logic:C ++ 0xは、ガベージコレクションのないクロージャーを通常のトリックで提供します->変数がスコープ外になり、参照に固執している場合、参照の使用は未定義の動作です。だからそれは可能です...それは単に開発者に名誉を与えるだけです。
マチューM.

5

ファーストクラスの関数は、クロージャーなしではあまり面白くありません。

何らかの動的スコープの管理(ガベージコレクション)がなければ、閉鎖は実際には不可能です。C / C ++のパフォーマンスが非常に優れている理由の1つは、メモリを手動で管理する言語をコンパイルする方がはるかに簡単であるため、C / C ++を式から除外できることです。

そして、はい、OOPの影響の問題があります。メソッドとプロパティの分離はなくなりました。メソッド自体は、関数を値として受け入れるプロパティです。そのコンテキストでは、いつでも愚かなものを交換することができるため、メソッドをオーバーロードすることは本当に何を意味します。たとえば、言語全体に大きなパラダイムシフトを導入することなく、実際にJavaに追加できますか?コンストラクトが毎回同じように常に機能することを保証する構造を知っていることから人々が得る契約またはその感覚(IMO偽)はどこにありますか?オブジェクトに関連付けられた関数を、関数が最初は独立して存在することを許可した言語では別の生物としてメソッドとして扱うのが理にかなっているかもしれませんが、実際にはオプションではありません。

JavaScriptでは、OOPと機能が非常に密接に絡み合っており、一流のファンクが、そうでない言語ではボルトオンされている以外の何かとして見ることは個人的に難しいと思います。しかし、そのためには、オブジェクトとそのメソッド自体の高レベルの可変性や、あたかもそのオブジェクトのメンバーであるかのように関数を呼び出すことができるなど、他の多くのパラダイムシフトの変更が必要です。

言語は、大部分のことを成し遂げるための日曜大工でいっぱいの単なるツールセットではありません。それらはパラダイムです。接続されている(または接続されているように見える)方法であらゆる種類のアイデア、戦略、および意見の束。多くの場合、名詞や動詞はパラダイムにまったく適合しないか、せいぜい不完全な適合であるとして機能します。

そうは言っても、それらなしでコーディングすることを余儀なくされたとき、私は腕を失っているように感じます。


すべてのメソッドを封印済みとして扱うか、最も関心のあるものを封印するだけで大​​丈夫です。
アレクセイアヴェルチェンコ

@AlexeiAverchenko私はあなたがそれによって何を意味するのか100%確信がないと言ってうれしいです。申し訳ありませんが、今までのコメントを逃しました。グーグルの「封印された方法」。
エリックReppen

4

それは本当に不可能ではありません。しかし、それはさらに別の機能であり、複雑さの予算は限られています。それは言語設計者によって不必要であると考えられるかもしれません(あるいは、偶然にも機能を渡す必要があるのでしょうか?この言語はOSのプログラミング用です!)。また、他の言語との統合にはかなりの労力が必要になる場合があります。たとえば、関数型は、型システムへの深刻な追加を必要とする場合があります(Javaなど)。さらに、オーバーロードがある場合は(さらに指摘してくれた@Renesisに感謝します)。また、実行可能なものを利用するためにいくつかのライブラリコードを提供する必要があります-誰もmap自分自身を定義することを望みません。

また、言語の他の目標を達成するのが難しくなる可能性があります。

  • 最適化が「難しく」なります(多くの場合、実際には難しくありませんが、慣れているものとは異なるアプローチが必要です)。たとえば、グローバル関数が再割り当てされる可能性がある場合、fインライン化する前に再割り当てされないことを証明する必要があります。
  • 同様に、関数をフル機能のオブジェクトにする場合、それに関連するオーバーヘッドを取り除き、引数をプッシュしてアドレスを返してジャンプするのと同じくらい効率的な(速度空間的に)呼び出しを行うスマートコンパイラとJITが必要ですいくつかのアドレス。
  • すでに述べたように、それは別の完全な機能であり、さらに別のパラダイムをサポートするための最初のステップです-単純な言語が必要な場合は、おそらく他のものを投げずにファーストクラスの機能を追加する余裕はありませんでる。
  • おそらく、それは単に他の言語とうまく調和しないでしょう。たとえば、Smalltalk以来OOPの最高の化身となるように言語を設計する場合、別の非常に異なるパラダイムを提供するのではなく、それに焦点を当てたいと思うかもしれません。特に、2つを統合するのが難しい場合(上記を参照)。N個のパラダイムがうまくできていれば、N + 1個のパラダイムがひどくできているよりも、プログラムを作成するのに適しています。

同様に、プログラミング言語L1がまったく異なる言語L2の機能Fを持たない理由を尋ねることができます。


1

最初の問題は、オブジェクト指向と機能を混在させることができないという誤解だと思います。JavaScriptActionScriptPythonC#F#の両方として、少なくともWikipediaで説明されている言語の簡単なリスト。

2番目の問題は、一流の関数の定義のようです。たとえば、C#がそれらを持っていると考えないのはなぜですか。

私は関数型言語の専門家ではないので、間違っている場合はコメントで修正してください。しかし、私の理解では、一流の関数を含めること自体が、言語が関数型パラダイムをサポートするかどうかを定義するということです

本当の質問は何ですか?

だから、オブジェクト指向言語も機能的であり、これらの言語にはファーストクラスの機能が含まれていることを理解すると、なぜあなたが探している質問は、オブジェクト指向言語にファーストクラスの機能が含まれないのですか?

関数のオーバーロード

この主な理由の1つは、言語が関数のオーバーロードをサポートすることを選択した場合に、ファーストクラス関数を定義するのが難しいことです(Javaの例)。

public int dispatchEvent(Event event);
public int dispatchEvent(String event, Object data);

dispatchEvent変数はどの関数を参照しますか?

クラスベースのプログラミング

クラスベースのプログラミングは、言語がファーストクラスのオブジェクトをサポートすることを妨げませんが、より混乱させたり、答えられる質問を追加したりできます。

例えば、ActionScriptは、ECMAScript言語として、JavaScriptのようなはるかに機能的なパラダイムで始まりました。関数は本質的にオブジェクトにバインドされていませんでした。実行時のスコープであるため、基本的にどのオブジェクトでも呼び出すことができました。

(動的ではない)クラスを追加すると、クラス自体だけでなく、本質的にインスタンスにバインドされている関数があります。これは、Function.apply私が正直に彼らがそれをどのように扱ったかを見つけるために掘り下げていないという仕様にいくつかのしわを投げます。


3
「一流の関数自体を含めることで、多少なりとも言語が機能するようになります。」- 違う。はい、それは前提条件です。しかし、(3つだけを挙げると)可変状態の回避、シーケンシャルステートメントではなく式と関数アプリケーションへのフォーカス、参照の透明性の強調など、それだけではありません。

@delnan正しいウィキペディアに行くべきです...「関数型言語」と「関数型パラダイムをサポートする言語」が異なる場合を除きます。
ニコール

1
@Rensis:それらは異なるものです。Cでオブジェクト(vtableを含む)のようなものを作成できますが、見た目は美しくありません。「ファーストクラスの機能を持っている」から「機能的な言語である」に移行することはそれほど悪くはありませんが、それでも違いです。また、wikiには(正しく)リンクしたページに「これらの機能は関数型プログラミングスタイルに必要です[...]」と記載されています。(つまり、「定義機能」ではありません)、FPのページに他のいくつかの機能をリストします。

@delnan、申し分なく、言葉遣いを修正しました。私は、言語が機能的パラダイムをサポートしていると見なされるための条件を意味しました-私がリストしたそれらの言語のそれぞれのWikipediaページもそうです。関数型プログラミングスタイルの一部であると言うつもりはありませんでした。
ニコール

0

私自身も同じことを考えました。ラムダを使用した言語になったら、LOTを使用します。PHPでさえも、PHP 5.3でクロージャを実行できることに気付いたとき、より良くなります(lispほどではありませんが、それでもなお優れています)

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