本当に建設的な答えではなく、いくつかの考えです。まず、免責事項 - 以下で説明する方法を推奨するものではありません (おそらく一般的にはそうではありません)。述べられた目標に関して - 私はその考えを大いに支持します。冗長性を減らすことができることは素晴らしいことです (少なくとも、ソロ開発者の個人的なニーズにとって)。ツールに関して: 私は 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 名の短い名前をハードコードし、それをコードの一部にラップします (ただし、コードの強調表示は失われます)。私は一般的にこの方法を推奨しているわけではないことに注意してください - 私は楽しみのために、そして行数を少し減らすためにそれをしました。しかし、少なくとも、これはインタラクティブでもパッケージでも機能するという意味で普遍的です。中置演算子ができない、優先順位が変えられない、などなどですが、作業はほぼゼロ。