web-dev-qa-db-ja.com

C#Dev-Lispを試しましたが、取得できません

CLと少しのClojureの両方でLISPについて学び、LISPを使って数か月経った後も、C#の代わりに何かを書こうとする説得力のある理由はまだわかりません。

私は本当にいくつかの説得力のある理由、または誰かが私が何かが欠けている本当に大きいであることを指摘してほしいです。

LISPの長所(私の研究による):

  • コンパクトで表現力豊かな表記法-C#よりも確かにそうですが、私はそれらのアイデアをC#でも表現できるようです。
  • 関数型プログラミングの暗黙的なサポート-LINQ拡張メソッドを使用したC#:
    • mapcar = .Select(lambda)
    • mapcan = .Select(lambda).Aggregate((a、b)=> a.Union(b))
    • car/first = .First()
    • cdr/rest = .Skip(1)....など.
  • ラムダおよび高次関数のサポート-C#にはこれがあり、構文は間違いなく単純です:
    • "(lambda(x)(body))"対 "x =>(body)"
    • "#(" with "%"、 "%1"、 "%2" is nice is in Clojure
  • オブジェクトから分離されたメソッドディスパッチ-C#には、拡張メソッドを通じてこれがあります。
  • マルチメソッドディスパッチ-C#にはネイティブではありませんが、数時間で関数呼び出しとして実装できます
  • コードはデータ(およびマクロ)です-マクロを「取得した」ことはないかもしれませんが、マクロのアイデアを関数として実装できない単一の例を見たことはありません。 「言語」を変えることはありませんが、それが強みかどうかはわかりません
  • DSL-関数構成を通じてのみそれを行うことができます...しかしそれは機能します
  • 型なしの「探索的」プログラミング-構造体/クラスの場合、C#の自動プロパティと「オブジェクト」は非常にうまく機能し、進むにつれてより強力な型に簡単にエスカレートできます
  • Windows以外のハードウェアで動作します-そうですか?大学の外では、自宅でWindowsを実行していない人、または少なくともVM * nix/MacのWindowsを使用していない人を1人だけ知っています。思ったより重要で洗脳されたばかり...)
  • REPLボトムアップデザインの場合-わかりました。これは本当に素晴らしいと思います。C#では見落とします。

LISPに欠けているもの(C#、. NET、Visual Studio、Resharperが混在しているため):

  • 名前空間。静的メソッドを使用する場合でも、それらを「クラス」に結び付けてコンテキストを分類します(Clojureにはこれがあるようですが、CLにはないようです)。
  • 優れたコンパイルおよび設計時サポート
    • 型システムを使用すると、渡すデータ構造の「正確さ」を判断できます
    • スペルミスはリアルタイムで下線が引かれます。実行時まで知る必要はありません
    • コードの改善(命令型の代わりにFPアプローチを使用するなど)が自動推奨されます
  • GUI開発ツール:WinFormsとWPF(ClojureがJava GUIライブラリにアクセスできることは知っていますが、私にはまったく関係ありません。)
  • GUIデバッグツール:ブレークポイント、ステップイン、ステップオーバー、値インスペクター(テキスト、xml、カスタム)、ウォッチ、スレッドごとのデバッグ、条件付きブレークポイント、任意のレベルのコードにジャンプする機能を備えたコールスタックウィンドウスタック
    • (公平を期すために、Emacs + Slimeを使用した私の気付はこれの一部を提供しているように見えましたが、私はVS GUIドリブンアプローチに不満です)

私はLISPを取り巻く誇大宣伝が本当に好きで、それにチャンスを与えました。

しかし、LISPでC#で同様にできないことはありますか? C#では少し冗長かもしれませんが、オートコンプリートも使用できます。

何が欠けていますか?なぜClojure/CLを使用する必要があるのですか?

37

マクロを使用すると、コンパイラーを記述せずに言語を快適に保つことができます。 C#のような言語のDSLは、通常、ランタイムインタープリターに相当します。ドメインによっては、パフォーマンス上の理由で問題が発生する可能性があります。 速度は重要です、そうでなければ、C#ではなくインタープリター言語でコーディングすることになります。

また、マクロを使用すると、人的要因を考慮することもできます。特定のDSLで最もユーザーフレンドリーな構文は何ですか。 C#では、構文に関してできることはあまりありません。

したがって、LISPではparticipateefficiencyへのパスを犠牲にすることなく、言語設計で使用できます。そして、これらの問題はyoには関係ないかもしれませんが、すべての有用なプロダクション指向プログラミング言語の基礎となるため、非常に重要です。 C#では、この基本的な要素は、せいぜい非常に限られた形式で公開されます。

マクロの重要性は他の言語でも失われません-テンプレートHaskell、camlp4が思い浮かびます。しかし、これもまたsabilityの問題です。これまでのLISPマクロは、コンパイル時変換の最もユーザーフレンドリーでありながら強力な実装です。

つまり、C#のような言語で一般的に行われていることは、DSIL(ドメイン固有解釈言語)を構築することです。 LISPは、もっと根本的なDSP(ドメイン固有パラダイム)を構築する機会を提供します。ラケット(以前のPLTスキーマ)は、この点で特に刺激的です。それらには、遅延言語(Lazy Racket)、型付き言語(Typed Racket)、Prolog、およびDatalogがすべて、マクロを介して慣用的に埋め込まれています。これらすべてparadigmsは、大規模なクラスの問題に対する強力なソリューションを提供します。問題は、命令型プログラミングやFPパラダイムによっても最適に解決されません。

23
dnolen

もともとLispでしか利用できなかったほとんどすべてのものは、ありがたいことに他の多くの現代言語に移行しています。最大の例外は、「コードはデータである」という哲学とマクロです。

コードはデータ(およびマクロ)です-マクロを「取得した」ことはないかもしれませんが、マクロのアイデアを関数として実装できない単一の例を見たことはありません

ええ、マクロは理解するのが難しいです。メタプログラミングは、一般的に理解しにくいものです。関数として実装できるanyマクロを見た場合、プログラマはそれを間違っていました。マクロは、関数が機能しない場合にのみ使用してください。

マクロの「hello world」の例は、condに関して「if」を書くことです。マクロの力を学ぶことに本当に興味がある場合は、関数を使用してclojureで「my-if」を定義し、それがどのように壊れるかを確認してください。私が神秘的であるという意味ではありません。説明だけでマクロを理解し始める人を見たことがありませんが、このスライドショーはかなり良いイントロです: http://www.slideshare.net/pcalcado/LISP -macros-in-20-minutes-featuring-clojure-presentation

私は小さなプロジェクトを持っていて、マクロを使用して文字通り数百/数千行のコードを保存しました(Javaの場合と比較して)。 Clojureの多くはClojureで実装されていますが、これはマクロシステムのためにのみ可能です。

15
mblinn

私はCommon LISPの専門家ではありませんが、C#とClojureの両方をある程度知っているので、これが有用な見方であることを願っています。

  • 単純な構文=> power-Lispは、機能する可能性のある最も単純な構文に関するものです。 S-expressions で十分です。 「(function-call arg1 arg2 arg3)」を手に入れたら、基本的にはそれがわかります。残りは、適切な関数呼び出しと引数を選択するだけです。ほとんど単純なように見えますが、この単純さはLispに非常に強力で柔軟性を与え、特にLISPが有名なメタプログラミング機能を有効にするのは事実です。例えばマクロが同じ引数でいくつかの異なる関数を呼び出すようにしたい場合は、次のようにします(これはではありませんランタイム関数アプリケーションではありません-コンパイルされたコードを生成するマクロです)すべての個別の関数呼び出しを手動で記述したかのように):
(defmacro print-many [functions args]  
  `(do   
     ~@(map   
        (fn [function] `(println (~function ~@args)))   
        functions)))

(print-many [+ - * /] [10 7 2])  
19  
1  
140  
5/7
  • 信じられないほど単純な構文の結果として、LISPの"code is data"哲学は、関数の構成/テンプレート/ジェネリックなどで実行できるものよりもはるかに強力です。 DSLだけでなく、コンパイル時の言語の基本的な機能としてのコード生成と操作です。これらの種類の機能をC#やJavaなどの homoiconic 以外の言語で取得しようとすると、最終的にはLISPの再発明につながります。したがって、有名な Greenspuns Tenth Rule :「十分に複雑なCまたはFortranプログラムには、Common LISPの半分のアドホックで非公式に指定され、バグが多く、遅い実装が含まれています」。あなたが自分のアプリケーション内で完全なテンプレート/フロー制御言語を発明していることに気付いたなら、おそらく私が何を言っているのか知っているでしょう...

  • Concurrencyは、(他のLispと比較しても)Clojureのユニークな強みですが、プログラミングの将来が高度にマルチスケールに拡張するアプリケーションを作成する必要があると確信している場合コアマシンの場合、実際にこれを調べる必要があります。これはかなり画期的なことです。 Clojure STM(ソフトウェアトランザクションメモリ)が機能するのは、Clojureが不変性と新規のIDと状態の分離Richアイデンティティと状態に関するHickeyの優れたビデオ )。 APIの大部分が変更可能なオブジェクトで機能する言語/ランタイム環境に、この種の同時実行機能を移植するのは非常に困難です。

  • 関数型プログラミング-Lispは、高次関数を使用したプログラミングを強調しています。 OOオブジェクトでクロージャー/関数オブジェクトなどを使用してエミュレートできるのは当然ですが、言語と標準ライブラリ全体がこの方法でコードを記述できるように設計されている点が異なります。たとえば、Clojure シーケンスはレイジー であるため、C#/ JavaのArrayListsまたはHashMapsとは異なり、無限に長くなる可能性があります。これにより、一部のアルゴリズムをはるかに表現しやすくなります。以下は、フィボナッチ数の無限リストを実装します。

    (def fibs (lazy-cat '(0 1) (map + fibs (drop 1 fibs))))

  • 動的型付け-Lispは、関数型プログラミング言語の範囲の「動的」端にある傾向があります(静的型の非常に強力で美しい概念を持つHas​​kellのような言語とは対照的) )。これには長所と短所の両方がありますが、動的言語は柔軟性が高いため、プログラミングの生産性を優先する傾向があると私は主張します。この動的型付けは、実行時のパフォーマンスコストがわずかですが、気になる場合は、コードに型ヒントを追加して、静的型付けを行うことができます。基本的には、デフォルトで利便性があり、それを取得するために少し余分な作業を行う場合はパフォーマンスが得られます。

  • インタラクティブ開発-実際、私はC#4.0でREPLのようなものを手に入れることができると思いますが、LISPではこれは目新しいものではなく標準的な方法です。コンパイル/ビルド/テストサイクルを実行する必要はまったくありません。実行中の環境で直接コードを記述し、後でそれをソースファイルにコピーするだけです。それはあなたにコーディングの非常に異なる方法を教えます、そこであなたはすぐに結果を見て、そしてあなたの解決策を繰り返し改良します。

あなたが「欠けている」と見ているものについてのいくつかの簡単なコメント:

  • あなたが言うように、Clojureには名前空間があります。実際、これらは動的な名前空間です。実行時に更新できます-これは、インタラクティブな開発に驚くべき利点を提供します。実行中のスレッドのノーズの下で関数を再定義したり、ライブデータ構造をハッキングしたりする楽しみがたくさんあります。
  • コンパイル/設計時サポート-REPLでコーディングしている場合はあまり関係ありません-実行して結果を直接確認するだけです。そうは言っても、ClojureはIDEサポートの改善を始めています。 Eclipse 用のCounterClockwiseプラグイン。
  • GUI開発-はい、新しいAPIを学ぶ必要がありますが、言語を切り替えるときには常にそうなります。良い知らせは、Java APIはそれほど難しくなく、かなり使いやすいように見える興味深いClojure固有のラッパー/サンプル。素敵な例については、 Clojure GUI開発に関するこの質問 を参照してください
  • GUIデバッグ:これは、CounterClockwiseを使用している場合はEclipseのGUIデバッガーで動作し、Netbeansを使用している場合はEnclojureで動作します。そうは言っても、私はこの機能を使用しません-REPLでのインタラクティブなデバッグの方が生産的だと思います。

私は個人的にClojure/LISPの利点を説得力があると感じており、C#/ Javaに戻る予定はありません(すべての有用なライブラリを借りるのに必要なものを超えています!)。

しかし、実際にすべてのことを理解するのに数か月かかりました。 LISP/Clojureを啓発的な学習体験として学ぶことに本当に興味がある場合は、飛び込んでいくつかのことを強制することに勝るものはありません.....

14
mikera

C#には多くの機能がありますが、ミックスの感じは異なります。一部の言語に機能があるということは、それが使いやすく、パラダイムであり、他の言語とうまく統合されていることを意味するものではありません。

一般的なLISPには次の組み合わせがあります。

  • データ構文としてのs式
  • データとしてのコードは、マクロやその他の記号計算手法につながります
  • 動的言語によりランタイムの変更が可能(遅延バインディング、MOPなど)
  • 強く型付けされた、動的に型付けされた
  • インクリメンタルコンパイラーまたはインタープリターとのインタラクティブな使用
  • コア実行エンジンとしてのエバリュエーター
  • ガベージコレクションによるマネージメモリ
  • 命令型、関数型、オブジェクト指向プログラミングを多用したハイブリッド言語。他のパラダイム(ルール、ロジック、制約など)を追加できます。

今、C#のような他の言語にもそれがあります。しかし、多くの場合、同じように強調されていません。

C#には

  • Cのような構文
  • いくつかのFP機能を備えた、ほとんどが命令型のオブジェクト指向
  • 静的に型付けされた
  • 主にバッチコンパイラでのバッチ使用
  • ガベージコレクションによるマネージメモリ

LISPのように広く使用されていない場合、C#にコード操作機能の例があることは役に立ちません。 LISPでは、あらゆる種類の単純な方法や複雑な方法でマクロを多用しないソフトウェアは多くありません。コード操作の使用は、LISPの本当に大きな機能です。多くの言語で一部の用途をエミュレートすることは可能ですが、LISPのように中心的な機能にはなりません。例については、「On LISP」や「Practical Common LISP」などの書籍を参照してください。

インタラクティブ開発についても同様です。大規模なCADシステムを開発する場合、開発のほとんどはエディターからインタラクティブに行われ、REPL-実行中のCADアプリケーション。多くの場合、C#または他の言語でその多くをエミュレートできます-多くの場合、拡張言語を実装することによって。LISPの場合、変更を追加するために開発中のCADアプリケーションを再起動するのは愚かですCADシステムには、CADオブジェクトとそのオブジェクトを説明するための(マクロとシンボリック記述の形式で)言語機能を追加した拡張LISPも含まれます。関係(part-of、contained、...)C#でも同様のことができますが、LISPではこれがデフォルトの開発スタイルです。

インタラクティブな開発プロセスを使用して複雑なソフトウェアを開発する場合、またはソフトウェアにかなりの象徴的な部分(メタプログラミング、その他のパラダイム、コンピュータ代数、作曲、計画など)がある場合、LISPが適しています。

Windows環境で作業している場合(私はそうしません)、C#はMicrosoftの主要な開発言語であるため、利点があります。 Microsoftは、どのようなフォームLISPもサポートしていません。

あなたが書く:

  • 名前空間。静的メソッドを使用する場合でも、それらを「クラス」に結び付けてコンテキストを分類します(Clojureにはこれがあるようですが、CLにはないようです)。

一般的なLISPはクラスに名前空間をアタッチしません。名前空間は、シンボルパッケージによって提供され、クラスから独立しています。 CLOSを使用する場合は、オブジェクト指向プログラミングへのアプローチを変更する必要があります。

  • コンパイルと設計時の優れたサポートにより、タイプシステムにより、スペルミスのあるものに渡すデータ構造の「正確さ」をリアルタイムで下線付きで判断できます。コードの改善(命令型の代わりにFPアプローチを使用するなど)が自動提案されることを知るために、ランタイムまで待つ必要はありません。

LISPコンパイラを使用します。不明な変数について通知し、スタイルの推奨事項がある場合があります(使用するコンパイラーによって異なります)、効率のヒントを提供します...コンパイラーはキーストロークで操作できます。

  • GUI開発ツール:WinFormsとWPF(ClojureがJava GUIライブラリにアクセスできることは知っていますが、私にはまったく関係ありません。)

LispWorksやAllegro CLなどの商用Lispは、Windowsでも同様の機能を提供します。

  • GUIデバッグツール:ブレークポイント、ステップイン、ステップオーバー、値インスペクター(テキスト、xml、カスタム)、ウォッチ、スレッドごとのデバッグ、条件付きブレークポイント、任意のレベルのコードにジャンプする機能を備えたコールスタックウィンドウスタック内(公平に言うと、Emacs + Slimeを使用した私の気遣いはこれの一部を提供しているように見えましたが、私はVS GUIドリブンアプローチに不慣れです)

LispWorksやAllegro CLなどの商用Lispは、Windowsでそれらすべてを提供します。

10
Rainer Joswig

レーニア・ジョスウィッグはそれを最高だと言った。

私にとって、LISPの機能のリストを見ただけでは、LISPのパワーを理解することはできません。 LISP、特にCommon LISPの場合、全体は部分の合計よりも大きくなります。 REPLプラスs式プラスマクロプラスマルチメソッドディスパッチプラスクロージャプラスパッケージプラスCLOSプラスリスタートプラスX、Y、Zだけではありません。すべてのシバンが巧みに統合されています。それは日常の経験は、他のプログラミング言語の日常の経験とは非常に異なります。

LISPは外観が異なり、使用方法も異なります。使用する場合、プログラミング方法が異なります。エレガントで、完全で、大きく、シームレスです。独自の傷やペッカディージョがないわけではありません。他の言語との比較は確かにありますが、先に出てこないかもしれません。しかしnoでは、LISPは言語XとREPLとマクロ、または言語Yとマルチメソッドのディスパッチと再起動だけです。

5
Chris Perkins
コードはデータ(およびマクロ)です-マクロを「取得した」ことはないかもしれませんが、マクロのアイデアを関数として実装できない単一の例を見たことはありません。 「言語」を変えることはありませんが、それが強みかどうかはわかりません

通常、マクロは、関数呼び出しとして表現できないものに使用する必要があります。 C#にスイッチのような条件が存在するかどうかはわかりません(スイッチ(フォーム){ケース...}としてCに存在するものに類似しています)があり、同じ制限に近いと仮定しましょう(整数型が必要です)。

次に、そのようなものを希望しているものの、文字列でディスパッチするものと想定します。 LISP(まあ、特にCommon LISPやおそらく他のものでも)では、これはマクロの「ただ」の部分であり、ユーザーが一致する定数文字列(おそらく困難ではない)に一致するようにユーザーを制限すると、(コンパイル時)計算することができますどのケースが一致するかを決定するための最小限のテストシーケンス(または、ハッシュテーブルを使用するか、おそらくクロージャーを格納する)。

これを関数(比較文字列、実行するケースとクロージャのリスト)として表現することは可能かもしれませんが、おそらく「通常のコード」のようには見えません。そのため、LISPマクロは確実に勝利します。かなりの数のマクロを使用したか、defundefmacrosetfcondloopおよびその他多数。

3
Vatine

これは私が見つけた最高の説明記事で、LISPアドボカシーの表面から読者を導き、使用されている概念のより深い意味合いのいくつかを示しています。

http://www.defmacro.org/ramblings/LISP.html

他の場所でこのような考えを読んだことを思い出します。他の言語がLISPのさまざまな機能を採用しています。ガベージコレクション、動的型付け、無名関数、クロージャーにより、より優れたC++/C/ALGOLを生成します。ただし、LISPの機能を最大限に活用するには、LISPのすべての基本機能が必要です。その時点で、LISPの別の方言、つまり50年以上にわたって何らかの形で使用されてきた言語の異なるファミリがあります。

2
spacebat