不是一个真正有建设性的答案,只是一些想法。首先,免责声明 - 我不建议将下面描述的任何方法作为良好实践(也许通常它们不是),它们只是似乎解决您的特定问题的一些可能性。关于既定目标 - 我非常支持这个想法,能够减少冗长是很棒的(至少对于独立开发人员的个人需求)。至于工具:我对 Notation 包的经验很少,但是,无论是否使用它或编写一些自定义的框操作预处理器,我的感觉是输入表达式必须由 Mathematica 解析器解析成框的整个事实严重限制了一些可以做的事情。此外,正如在另一个回复中已经提到的那样,在包中使用它可能会遇到困难。
如果有一些类似 的钩子,那将是最简单$PreRead
的,这将允许用户拦截输入字符串并将其处理为另一个字符串,然后再将其提供给解析器。这将允许人们编写一个在字符串级别运行的自定义预处理器 - 或者如果您愿意,您可以将其称为编译器 - 这将采用您设计的任何语法的字符串并从中生成 Mathematica 代码。我不知道这样的钩子(当然这可能是我的无知)。缺少这一点,可以使用例如程序样式的单元格,也许可以编写一些按钮,这些按钮从这些单元格中读取字符串并调用此类预处理器以生成 Mathematica 代码并将其粘贴到原始代码所在的单元格旁边的单元格中。
如果您想要的语言是一些简单的语言(至少就其语法和语法而言),这种预处理器方法将工作得最好,因此很容易进行词法分析和解析。如果您想要 Mathematica 语言(其完整的语法模数只是您想要更改的几个元素),在这种方法中,您不走运,因为无论您的更改有多少和“轻量级”,您d 需要几乎完全重新实现 Mathematica 解析器,只是为了进行这些更改,如果您希望它们可靠地工作。换句话说,我要说的是,IMO 编写一个预处理器要容易得多,它可以从一些类似 Lisp 的语言生成 Mathematica 代码,几乎没有语法,而不是尝试对标准 mma 进行一些语法修改。
从技术上讲,编写这种预处理器的一种方法是使用 Lex(Flex) 和 Yacc(Bison) 等标准工具来定义语法并生成解析器(比如用 C 语言)。这样的解析器可以通过 MathLink 或 LibraryLink(在 C 的情况下)插回 Mathematica。它的最终结果将是一个字符串,当被解析时,它将成为一个有效的 Mathematica 表达式。此表达式将代表您已解析代码的抽象语法树。比如像这样的代码(Fold
这里介绍新的语法for)
"((1|+|{2,3,4,5}))"
可以被解析成类似的东西
"functionCall[fold,{plus,1,{2,3,4,5}}]"
这种预处理器的第二个组件将用 Mathematica 编写,可能是基于规则的样式,以从 AST 生成 Mathematica 代码。生成的代码必须以某种方式保持未评估。对于上面的代码,结果可能看起来像
Hold[Fold[Plus,1,{2,3,4,5}]]
最好是在 Mathematica 中可以使用 Lex(Flex)/Yacc(Bison) 等工具的类似物(我的意思是绑定,这将需要一个人只在 Mathematica 中编写代码,然后自动生成 C 解析器,然后将其插入通过 MathLink 或 LibraryLink 到内核)。我可能只希望它们将在未来的某些版本中可用。缺少这一点,我描述的方法将需要大量的低级工作(如果您愿意,可以使用 C 或 Java)。不过我觉得还是可以的。如果您可以编写 C(或 Java),您可能会尝试编写一些相当简单(就语法/语法而言)的语言 - 这可能是一个有趣的项目,并且会了解更复杂的语言会是什么样子一。我将从一个非常基本的计算器示例开始,也许将那里的标准算术运算符更改为 Mathematica 本身无法正确解析的一些更奇怪的运算符,以使其更有趣。为了避免 MathLink/LibraryLink 的复杂性并只是测试,您可以从 Mathematica 调用生成的可执行文件Run
,将代码作为命令行参数之一传递,并将结果写入临时文件,然后将其导入 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}]];]];
您需要一些包含大量单词的训练文本作为字符串作为第二个参数传递,第一个参数是校正器的函数名称。这是 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 名称的短名称,然后将其包裹在您的代码段(但是您将失去代码突出显示)。请注意,我通常不提倡这种方法 - 我这样做只是为了好玩并减少行数。但至少,从某种意义上说,这是通用的,它既可以交互地工作,也可以在包中工作。不能做中缀运算符,不能改变优先级等等,但几乎是零工作。