CLと少しのClojureの両方でLISPについて学び、LISPを使って数か月経った後も、C#の代わりに何かを書こうとする説得力のある理由はまだわかりません。
私は本当にいくつかの説得力のある理由、または誰かが私が何かが欠けている本当に大きいであることを指摘してほしいです。
LISPの長所(私の研究による):
LISPに欠けているもの(C#、. NET、Visual Studio、Resharperが混在しているため):
私はLISPを取り巻く誇大宣伝が本当に好きで、それにチャンスを与えました。
しかし、LISPでC#で同様にできないことはありますか? C#では少し冗長かもしれませんが、オートコンプリートも使用できます。
何が欠けていますか?なぜClojure/CLを使用する必要があるのですか?
マクロを使用すると、コンパイラーを記述せずに言語を快適に保つことができます。 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パラダイムによっても最適に解決されません。
もともと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で実装されていますが、これはマクロシステムのためにのみ可能です。
私はCommon LISPの専門家ではありませんが、C#とClojureの両方をある程度知っているので、これが有用な見方であることを願っています。
(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は、関数型プログラミング言語の範囲の「動的」端にある傾向があります(静的型の非常に強力で美しい概念を持つHaskellのような言語とは対照的) )。これには長所と短所の両方がありますが、動的言語は柔軟性が高いため、プログラミングの生産性を優先する傾向があると私は主張します。この動的型付けは、実行時のパフォーマンスコストがわずかですが、気になる場合は、コードに型ヒントを追加して、静的型付けを行うことができます。基本的には、デフォルトで利便性があり、それを取得するために少し余分な作業を行う場合はパフォーマンスが得られます。
インタラクティブ開発-実際、私はC#4.0でREPLのようなものを手に入れることができると思いますが、LISPではこれは目新しいものではなく標準的な方法です。コンパイル/ビルド/テストサイクルを実行する必要はまったくありません。実行中の環境で直接コードを記述し、後でそれをソースファイルにコピーするだけです。それはあなたにコーディングの非常に異なる方法を教えます、そこであなたはすぐに結果を見て、そしてあなたの解決策を繰り返し改良します。
あなたが「欠けている」と見ているものについてのいくつかの簡単なコメント:
私は個人的にClojure/LISPの利点を説得力があると感じており、C#/ Javaに戻る予定はありません(すべての有用なライブラリを借りるのに必要なものを超えています!)。
しかし、実際にすべてのことを理解するのに数か月かかりました。 LISP/Clojureを啓発的な学習体験として学ぶことに本当に興味がある場合は、飛び込んでいくつかのことを強制することに勝るものはありません.....
C#には多くの機能がありますが、ミックスの感じは異なります。一部の言語に機能があるということは、それが使いやすく、パラダイムであり、他の言語とうまく統合されていることを意味するものではありません。
一般的なLISPには次の組み合わせがあります。
今、C#のような他の言語にもそれがあります。しかし、多くの場合、同じように強調されていません。
C#には
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もサポートしていません。
あなたが書く:
一般的なLISPはクラスに名前空間をアタッチしません。名前空間は、シンボルパッケージによって提供され、クラスから独立しています。 CLOSを使用する場合は、オブジェクト指向プログラミングへのアプローチを変更する必要があります。
LISPコンパイラを使用します。不明な変数について通知し、スタイルの推奨事項がある場合があります(使用するコンパイラーによって異なります)、効率のヒントを提供します...コンパイラーはキーストロークで操作できます。
LispWorksやAllegro CLなどの商用Lispは、Windowsでも同様の機能を提供します。
LispWorksやAllegro CLなどの商用Lispは、Windowsでそれらすべてを提供します。
レーニア・ジョスウィッグはそれを最高だと言った。
私にとって、LISPの機能のリストを見ただけでは、LISPのパワーを理解することはできません。 LISP、特にCommon LISPの場合、全体は部分の合計よりも大きくなります。 REPLプラスs式プラスマクロプラスマルチメソッドディスパッチプラスクロージャプラスパッケージプラスCLOSプラスリスタートプラスX、Y、Zだけではありません。すべてのシバンが巧みに統合されています。それは日常の経験は、他のプログラミング言語の日常の経験とは非常に異なります。
LISPは外観が異なり、使用方法も異なります。使用する場合、プログラミング方法が異なります。エレガントで、完全で、大きく、シームレスです。独自の傷やペッカディージョがないわけではありません。他の言語との比較は確かにありますが、先に出てこないかもしれません。しかしnoでは、LISPは言語XとREPLとマクロ、または言語Yとマルチメソッドのディスパッチと再起動だけです。
コードはデータ(およびマクロ)です-マクロを「取得した」ことはないかもしれませんが、マクロのアイデアを関数として実装できない単一の例を見たことはありません。 「言語」を変えることはありませんが、それが強みかどうかはわかりません
通常、マクロは、関数呼び出しとして表現できないものに使用する必要があります。 C#にスイッチのような条件が存在するかどうかはわかりません(スイッチ(フォーム){ケース...}としてCに存在するものに類似しています)があり、同じ制限に近いと仮定しましょう(整数型が必要です)。
次に、そのようなものを希望しているものの、文字列でディスパッチするものと想定します。 LISP(まあ、特にCommon LISPやおそらく他のものでも)では、これはマクロの「ただ」の部分であり、ユーザーが一致する定数文字列(おそらく困難ではない)に一致するようにユーザーを制限すると、(コンパイル時)計算することができますどのケースが一致するかを決定するための最小限のテストシーケンス(または、ハッシュテーブルを使用するか、おそらくクロージャーを格納する)。
これを関数(比較文字列、実行するケースとクロージャのリスト)として表現することは可能かもしれませんが、おそらく「通常のコード」のようには見えません。そのため、LISPマクロは確実に勝利します。かなりの数のマクロを使用したか、defun
、defmacro
、setf
、cond
、loop
およびその他多数。
これは私が見つけた最高の説明記事で、LISPアドボカシーの表面から読者を導き、使用されている概念のより深い意味合いのいくつかを示しています。
http://www.defmacro.org/ramblings/LISP.html
他の場所でこのような考えを読んだことを思い出します。他の言語がLISPのさまざまな機能を採用しています。ガベージコレクション、動的型付け、無名関数、クロージャーにより、より優れたC++/C/ALGOLを生成します。ただし、LISPの機能を最大限に活用するには、LISPのすべての基本機能が必要です。その時点で、LISPの別の方言、つまり50年以上にわたって何らかの形で使用されてきた言語の異なるファミリがあります。