私はスティーブン・ウルフラムの大ファンですが、彼は間違いなく彼自身のホーンを使いすぎることをoneしません。多くの参考文献で、彼はMathematicaを異なるシンボリックプログラミングパラダイムとして賞賛しています。私はMathematicaユーザーではありません。
私の質問は、このシンボリックプログラミングとは何ですか?また、関数型言語(Haskellなど)と比較してどうですか?
Mathematicaのシンボリックプログラミングは、検索と置換のルールを指定することでプログラミングする検索と置換のシステムと考えることができます。
たとえば、次のルールを指定できます
area := Pi*radius^2;
次回area
を使用すると、Pi*radius^2
に置き換えられます。ここで、新しいルールを定義するとします
radius:=5
これで、radius
を使用するたびに、5
に書き換えられます。 area
を評価すると、radius
の書き換えルールをトリガーするPi*radius^2
に書き換えられ、中間結果としてPi*5^2
を取得します。この新しいフォームは、^
操作の組み込みの書き換えルールをトリガーするため、式はPi*25
にさらに書き換えられます。適用可能なルールがないため、この時点で書き換えは停止します。
置換ルールを関数として使用することにより、関数型プログラミングをエミュレートできます。たとえば、追加する関数を定義する場合は、次のようにします。
add[a_,b_]:=a+b
add[x,y]
はx+y
に書き換えられます。数値a、bにのみ適用するように追加する場合は、代わりに行うことができます
add[a_?NumericQ, b_?NumericQ] := a + b
現在、add[2,3]
はルールを使用して2+3
に書き換えられ、5
の組み込みルールを使用して+
に書き換えられますが、add[test1,test2]
は変更されません。
インタラクティブな置換ルールの例を次に示します
a := ChoiceDialog["Pick one", {1, 2, 3, 4}]
a+1
ここで、a
はChoiceDialog
に置き換えられ、ポップアップでユーザーが選択した番号に置き換えられます。これにより、数量が数値になり、+
の置換ルールがトリガーされます。ここでは、「ChoiceDialog [some stuff]をユーザーがクリックしたボタンの値に置き換える」という行に沿った組み込みの置換ルールとしてChoiceDialog
を使用します。
ルールは、True
またはFalse
を生成するためにそれ自体がルールの書き換えを行う必要がある条件を使用して定義できます。たとえば、新しい方程式を解く方法を考案したが、その方法の最終結果が肯定的な場合にのみ機能すると考えているとします。次のルールを実行できます
solve[x + 5 == b_] := (result = b - 5; result /; result > 0)
ここでは、solve[x+5==20]
は15に置き換えられますが、solve[x + 5 == -20]
は、適用されるルールがないため変更されていません。このルールの適用を妨げる条件は/;result>0
です。 Evaluatorは基本的に、ルールアプリケーションの潜在的な出力を調べて、それを続行するかどうかを決定します。
Mathematicaの評価者は、すべてのパターンをそのシンボルに適用されるルールの1つで貪欲に書き換えます。細かな制御が必要な場合があります。そのような場合は、独自のルールを定義して、次のように手動で適用できます。
myrules={area->Pi radius^2,radius->5}
area//.myrules
これにより、結果の変更が停止するまで、myrules
で定義されたルールが適用されます。これはデフォルトのエバリュエーターに非常に似ていますが、いくつかのルールセットを用意して、それらを選択的に適用できます。より高度な 例 は、ルールアプリケーションのシーケンスを検索するPrologのようなエバリュエーターを作成する方法を示しています。
現在のMathematicaバージョンの欠点の1つは、Mathematicaのデフォルトエバリュエーターを使用する必要がある場合(Integrate
、Solve
などを使用するため)and評価のデフォルトシーケンスを変更したい。それは可能ですが、 複雑 であり、シンボリックプログラミングの将来の実装には、評価シーケンスを制御するよりエレガントな方法があると思います
「記号プログラミング」というフレーズを聞くと、LISP、Prolog、および(はい)Mathematicaがすぐに思い浮かびます。シンボリックプログラミング環境を、プログラムテキストを表すために使用される式がたまたま主要なデータ構造である環境として特徴付けます。その結果、データをコードに、またはその逆に簡単に変換できるため、抽象化に基づいて抽象化を構築することが非常に簡単になります。
Mathematicaはこの機能を大いに活用しています。 LISPおよびProlog(IMHO)よりもさらに重要です。
シンボリックプログラミングの例として、次の一連のイベントを考えます。次のようなCSVファイルがあります。
r,1,2
g,3,4
私はそのファイルを次の場所で読みました。
Import["somefile.csv"]
--> {{r,1,2},{g,3,4}}
結果データまたはコードですか?両方です。それはファイルの読み取りから生じるデータですが、たまたまそのデータを構築する式でもあります。ただし、コードが進むにつれて、この式は評価結果が単純であるため不活性です。
したがって、結果に変換を適用します。
% /. {c_, x_, y_} :> {c, Disk[{x, y}]}
--> {{r,Disk[{1,2}]},{g,Disk[{3,4}]}}
詳細にこだわることなく、起こったすべてのことは、Disk[{...}]
が各入力行の最後の2つの数値をラップしていることです。結果はデータ/コードのままですが、不活性のままです。別の変換:
% /. {"r" -> Red, "g" -> Green}
--> {{Red,Disk[{1,2}]},{Green,Disk[{3,4}]}}
はい、まだ不活性です。しかし、驚くべき偶然の一致により、この最後の結果は、たまたまグラフィック用のMathematicaの組み込みドメイン固有言語の有効なディレクティブのリストになりました。最後の変換、そして物事が起こり始めます:
% /. x_ :> Graphics[x]
--> Graphics[{{Red,Disk[{1,2}]},{Green,Disk[{3,4}]}}]
実際、その最後の結果は表示されません。構文糖の壮大な表示では、Mathematicaは赤と緑の円のこの図を表示します。
しかし、楽しみはそれだけではありません。シンタックスシュガーのすべての下に、まだシンボリックな表現があります。別の変換ルールを適用できます。
% /. Red -> Black
プレスト!赤い円が黒くなった。
記号プログラミングを特徴付けるのは、この種の「記号プッシュ」です。 Mathematicaプログラミングの大部分はこの性質のものです。
シンボリックプログラミングと関数型プログラミングの違いについては詳しく説明しませんが、いくつかの意見を述べます。
シンボリックプログラミングは、「式変換のみを使用してすべてをモデル化しようとするとどうなりますか?」という質問に対する答えとして見ることができます。対照的に、関数型プログラミングは、「関数のみを使用してすべてをモデル化しようとするとどうなりますか?」に対する答えと見ることができます。シンボリックプログラミングと同様に、関数型プログラミングを使用すると、抽象化のレイヤーをすばやく簡単に構築できます。ここで示した例は、機能的なリアクティブアニメーションアプローチを使用して、たとえばHaskellで簡単に再現できます。関数型プログラミングは、すべて関数の構成、高レベルの関数、コンビネーターに関するものです。関数を使ってできるすべての気の利いたことです。
Mathematicaはシンボリックプログラミング用に明らかに最適化されています。機能的なスタイルでコードを書くことは可能ですが、Mathematicaの機能的な機能は、実際には変換に対する薄いベニアにすぎません(そして、漏れやすい抽象化、下の脚注を参照)。
Haskellは、関数型プログラミング向けに明らかに最適化されています。コードをシンボリックスタイルで記述することは可能ですが、プログラムとデータの構文表現が非常に明確であり、エクスペリエンスが最適ではないことをしています。
結論として、関数型プログラミング(Haskellによって要約された)とシンボリックプログラミング(Mathematicaによって要約された)には区別があると主張します。両方を研究すれば、1つだけを研究することよりもはるかに多くのことを学べると思います。
うん、漏れやすい。これを試してください、例えば:
f[x_] := g[Function[a, x]];
g[fn_] := Module[{h}, h[a_] := fn[a]; h[0]];
f[999]
WRIに正式に報告され、承認されました。応答:Function[var, body]
の使用を避けます(Function[body]
は問題ありません)。
ここですでに述べたように、Mathematicaは多くの用語の書き換えを行います。たぶん、Haskellは最良の比較ではないかもしれませんが、 Pure はニースの機能的な用語書き換え言語です(Haskellのバックグラウンドを持つ人々には馴染みがあるはずです)。用語の書き換えに関するWikiページを読むと、いくつかのことがわかります。
Mathematicaは用語の書き換えを多用しています。この言語は、さまざまな形式の書き換えのための特別な構文、ルールと戦略の特別なサポートを提供します。そのパラダイムは「新しい」ものではなく、もちろんユニークなものでもありませんが、Axiomなどの他の強力なプレーヤーと並んで、この「シンボリックプログラミング」の最前線に間違いなく存在します。
Haskellとの比較については、定型ライブラリを廃棄することで多少の助けを借りてそこに書き直すこともできますが、動的に型付けされたMathematicaほど簡単ではありません。
シンボリックは関数と対比されるべきではなく、数値プログラミングと対比されるべきです。例として、MatLabとMathematicaを検討してください。行列の特性多項式が必要だとします。 Mathematicaでそれを行いたい場合、恒等行列(I)と行列(A)自体をMathematicaに取得して、これを行うことができます:
Det[A-lambda*I]
そして、私は特性多項式を取得します(おそらく特性多項式関数があることを気にしないでください)、一方で、MatLabにいた場合、ベースMatLabのためにそれを行うことはできません(おそらくベースのMatLab関数)は、有限精度の数値を計算するのが得意であり、そこにランダムなラムダ(シンボル)があるものではありません。あなたがしなければならないのは、アドオンのSymbolabを購入し、ラムダを独自のコード行として定義してから書き出すことです(Aマトリックスを有限精度の小数ではなく有理数のマトリックスに変換します) 、そしてこのような小さなケースではおそらくパフォーマンスの違いは目立たないでしょうが、おそらく相対速度の点ではMathematicaよりもはるかに遅くなります。
それが違いです、シンボリック言語は完全な精度で計算を行うことに興味があります(多くの場合、数値ではなく有理数を使用します)。目的の数値演算の高速化(MatLabは、C++などを除く高レベル言語ではこの点でほぼ無類です)およびシンボリック演算が苦手です。