6

Notationパッケージを使ってMathematicaで構文modを試しています。

私は特定の分野の数学表記には興味がありませんが、汎用構文の変更と拡張、特にMathematicaのVeryLongFunctionNamesの冗長性を減らしたり、扱いにくい構造をクリーンアップしたり、言語を心地よい方法で拡張したりする表記には興味がありません。

変更の例は、次のFold[f, x]ように評価するように定義することFold[f, First@x, Rest@x]
です。これはうまく機能し、非常に便利です。

もう1つは、Pythonに触発されたものとして*{1,2}評価することを定義することです。Sequence @@ {1,2}これはMathematicaで動作する場合と動作しない場合があります。

以下に対応する情報またはリンクを提供してください。

  • 表記法と構文変更の制限

  • 実装のヒントとコツ

  • 既存のパッケージ、例、または実験

  • なぜこれが良いまたは悪い考えであるか

4

3 に答える 3

5

本当に建設的な答えではなく、いくつかの考えです。まず、免責事項 - 以下で説明する方法を推奨するものではありません (おそらく一般的にはそうではありません)。述べられた目標に関して - 私はその考えを大いに支持します。冗長性を減らすことができることは素晴らしいことです (少なくとも、ソロ開発者の個人的なニーズにとって)。ツールに関して: 私は Notation パッケージの経験がほとんどありませんが、それを使用するか、カスタムのボックス操作プリプロセッサを作成するかどうかにかかわらず、入力式を Mathematica パーサーによってボックスに解析する必要があるという事実全体が私の感覚です。できることの数を大幅に制限します。さらに、すでに他の返信で述べたように、パッケージで使用するのは難しいでしょう。

のようなフックがあれば$PreRead、ユーザーが入力文字列をインターセプトして、パーサーに渡す前に別の文字列に処理できるようになると最も簡単です。これにより、文字列レベルで動作するカスタム プリプロセッサを作成することができます。または、必要に応じてコンパイラと呼ぶこともできます。このプリプロセッサは、設計した構文の文字列を取得し、そこから Mathematica コードを生成します。私はそのようなフックを認識していません (もちろん私の無知かもしれません)。それがない場合は、たとえばプログラムスタイルのセルを使用して、それらのセルから文字列を読み取り、そのようなプリプロセッサを呼び出して Mathematica コードを生成し、元のコードがあるセルの隣のセルに貼り付けるボタンをプログラムすることができます。

このようなプリプロセッサのアプローチは、必要な言語が単純な言語 (少なくとも構文と文法の点では) である場合に最適であり、字句解析と解析が容易です。Mathematica 言語(変更したい要素がわずかしかない完全な構文モジュロ)が必要な場合、このアプローチでは、変更がどれほど少なく「軽量」であっても、確実に動作させたい場合は、これらの変更を行うためだけに、Mathematica パーサーをほぼ完全に再実装する必要があります。言い換えれば、私が言いたいのは、標準のmmaにいくつかの構文変更を実装しようとするよりも、ほとんどまたはまったく構文を使用せずにLispのような言語から Mathematica コードを生成するプリプロセッサを作成する方がはるかに簡単だということです。

技術的には、このようなプリプロセッサを作成する 1 つの方法は、Lex(Flex) や Yacc(Bison) などの標準ツールを使用して文法を定義し、パーサーを生成することです (たとえば、C で)。このようなパーサーは、MathLink または LibraryLink (C の場合) を介して Mathematica にプラグインできます。その最終結果は文字列であり、解析すると有効な Mathematica 式になります。この式は、解析されたコードの抽象構文ツリーを表します。たとえば、次のようなコードです ( の新しい構文Foldが導入されています)。

"((1|+|{2,3,4,5}))"

次のようなものに解析できます

"functionCall[fold,{plus,1,{2,3,4,5}}]"

このようなプリプロセッサの 2 番目のコンポーネントは、AST から Mathematica コードを生成するために、おそらくルールベースのスタイルで Mathematica で記述されます。結果のコードは、何らかの形で未評価のままにしておく必要があります。上記のコードの場合、結果は次のようになります。

Hold[Fold[Plus,1,{2,3,4,5}]]

Lex(Flex)/Yacc(Bison) のようなツールの類似物が Mathematica 内で利用可能であれば最高です (バインディングを意味します。これは Mathematica でコードを書くだけで済み、そこから C パーサーを自動的に生成し、プラグインします) MathLink または LibraryLink のいずれかを介してカーネルに)。将来のいくつかのバージョンでそれらが利用可能になることを願うだけかもしれません. それが欠けていると、私が説明したアプローチでは、多くの低レベルの作業 (C、またはお好みで Java) が必要になります。それでもまだ可能だと思います。C (または Java) を書くことができる場合は、かなり単純な (構文/文法の点で) 言語を試してみてください。これは興味深いプロジェクトになる可能性があり、より複雑な言語ではどのようになるかについてのアイデアが得られます。 1。非常に基本的な電卓の例から始めます そしておそらく、そこにある標準の算術演算子を、Mathematica 自体が適切に解析できない奇妙なものに変更して、より興味深いものにします。最初はMathLink / LibraryLinkの複雑さを避けてテストするだけで、Mathematica から結果の実行可能ファイルを次のように呼び出すことができますRun、コマンドライン引数の1つとしてコードを渡し、結果を一時ファイルに書き込みます。これをMathematica にインポートします。電卓の例では、すべてを数時間で完了できます。

もちろん、特定の長い関数名だけを省略したい場合は、もっと簡単な代替手段があります - を使用Withしてそれを行うことができます。これがその実用的な例です - Peter Norvig のスペル修正プログラムの私の移植で、行数を減らすためにこの方法でだましました:

Clear[makeCorrector];
makeCorrector[corrector_Symbol, trainingText_String] :=
Module[{model, listOr, keys, words, edits1, train, max, known, knownEdits2},
(* Proxies for some commands - just to play with syntax a bit*)
With[{fn = Function, join = StringJoin, lower = ToLowerCase, 
 rev = Reverse, smatches = StringCases, seq = Sequence, chars = Characters, 
 inter = Intersection, dv = DownValues, len = Length, ins = Insert,
 flat = Flatten, clr = Clear, rep = ReplacePart, hp = HoldPattern},
(* body *)
listOr = fn[Null, Scan[If[# =!= {}, Return[#]] &, Hold[##]], HoldAll];
keys[hash_] := keys[hash] = Union[Most[dv[hash][[All, 1, 1, 1]]]];
words[text_] := lower[smatches[text, LetterCharacter ..]];
With[{m = model}, 
 train[feats_] := (clr[m]; m[_] = 1; m[#]++ & /@ feats; m)];
 With[{nwords = train[words[trainingText]], 
  alphabet = CharacterRange["a", "z"]},
  edits1[word_] := With[{c = chars[word]}, join @@@ Join[
     Table[
      rep[c, c, #, rev[#]] &@{{i}, {i + 1}}, {i, len[c] - 1}], 
     Table[Delete[c, i], {i, len[c]}], 
     flat[Outer[#1[c, ##2] &, {ins[#1, #2, #3 + 1] &, rep}, 
       alphabet, Range[len[c]], 1], 2]]];
  max[set_] := Sort[Map[{nwords[#], #} &, set]][[-1, -1]];
  known[words_] := inter[words, keys[nwords]]]; 
 knownEdits2[word_] := known[flat[Nest[Map[edits1, #, {-1}] &, word, 2]]];
 corrector[word_] := max[listOr[known[{word}], known[edits1[word]],
   knownEdits2[word], {word}]];]];

2 番目の引数として渡す文字列として多数の単語を含むトレーニング テキストが必要です。最初の引数は修正子の関数名です。Norvigが使用したものは次のとおりです。

text = Import["http://norvig.com/big.txt", "Text"];

あなたはそれを一度呼び出す、と言う

In[7]:= makeCorrector[correct, text]

そして、いくつかの単語で何度でも使用します

In[8]:= correct["coputer"] // Timing

Out[8]= {0.125, "computer"}

カスタムのWithような制御構造を作成できます。ここでは、最も煩わしい長い mma 名の短い名前をハードコードし、それをコードの一部にラップします (ただし、コードの強調表示は失われます)。私は一般的にこの方法を推奨しているわけではないことに注意してください - 私は楽しみのために、そして行数を少し減らすためにそれをしました。しかし、少なくとも、これはインタラクティブでもパッケージでも機能するという意味で普遍的です。中置演算子ができない、優先順位が変えられない、などなどですが、作業はほぼゼロ。

于 2011-03-26T23:53:02.440 に答える
3

完全な答えではありませんが、ここで学んだトリックを示すためだけに(記法よりもシンボルの再定義に関連していると思います):

Unprotect[Fold];
Fold[f_, x_] :=
  Block[{$inMsg = True, result},
    result = Fold[f, First@x, Rest@x];
    result] /; ! TrueQ[$inMsg];
Protect[Fold];

Fold[f, {a, b, c, d}]
(*
--> f[f[f[a, b], c], d]
*)

編集

以下について@rcollyerに感謝します(以下のコメントを参照)。

$inMsg 変数を使用して、必要に応じて定義をオンまたはオフに切り替えることができます。

$inMsg = False;
Fold[f, {a, b, c, d}]
(*
->f[f[f[a,b],c],d]
*)

$inMsg = True;
Fold[f, {a, b, c, d}]
(*
->Fold::argrx: (Fold called with 2 arguments; 3 arguments are expected. 
*)

Fold[f, {a, b, c, d}]

それはテスト中に非常に貴重です

于 2011-03-26T01:49:14.873 に答える
3

(私の最初の返信/投稿....優しくしてください)

私の経験からすると、この機能はプログラミングの袋小路のように見えます。カスタム表記を定義する機能は、「表記パレット」を使用して各カスタム表記を定義およびクリアすることに大きく依存しているようです。(「すべてが式です」... まあ、パレットを使用しなければならない記譜法などのあいまいなケースを除いて。) 残念。

Notation パッケージのドキュメントでは、これについて明示的に言及されているので、あまり文句を言うことはできません。

特定のノートブックでカスタム記法を定義したいだけなら、記法が役に立つかもしれません。一方、目標が YourOwnPackage.m にカスタム表記を実装して他の人に配布することである場合、問題が発生する可能性があります。(Box 構造に非常に精通している場合を除きますか?)

誰かがこれに関する私の無知を正すことができれば、あなたは私の月を作るでしょう!! :)

(記法を使用して、MMA に添字付きの変数をシンボルとして扱わせたいと考えていました。)

于 2011-03-26T11:58:53.270 に答える