我正在使用符号包在Mathematica中使用语法mods进行实验。
我对特定字段的数学表示法并不感兴趣,而是对通用语法的修改和扩展感兴趣,尤其是一些符号,这些符号可以减少Mathematica的VeryLongFunctionNames的冗长性,清理笨重的结构,或者以一种令人愉悦的方式扩展语言。
一个示例修改是将Fold[f, x]定义为Fold[f, First@x, Rest@x]。
这个很好用,而且很方便。
另一种方法是将*{1,2}定义为Sequence @@ {1,2},这是受Python启发的;这在Mathematica中可能有用,也可能不起作用。
请提供资料或链接,说明:
发布于 2011-03-26 23:53:02
不是很有建设性的回答,只是一些想法。首先,免责声明--我不建议下面描述为良好实践的任何一种方法(也许通常它们不是),它们只是一些似乎解决了您的具体问题的可能性。关于既定的目标--我非常支持这个想法,能够减少细节是很棒的(至少对于一个单独开发人员的个人需求来说是这样)。至于工具:我对符号包没有什么经验,但是,不管是否有人使用它或编写自定义的框操作预处理器,我的感觉是,输入表达式必须由Mathematica解析器解析成盒子这一事实严重限制了许多可以做的事情。此外,在软件包中使用它可能会有困难,正如其他答复中已经提到的那样。
如果有像$PreRead这样的钩子,这将是最简单的,这将允许用户拦截输入字符串并将其处理为另一个字符串,然后将其输入到解析器。这将允许您编写一个自定义的预处理程序,它在字符串级别上运行--或者您可以将它称为编译器(如果您愿意的话)--它将接受您设计的任何语法的字符串,并从它生成Mathematica代码。我不知道这样的勾当(当然,这可能是我的无知)。缺少这一点,我们就可以使用程序样式的单元格,也许还可以编写一些按钮,从这些单元格中读取字符串,并调用这样的预处理器来生成Mathematica代码,并将其粘贴到原代码所在的单元格中。
如果您想要的语言是一些简单的语言(至少在语法和语法方面),那么这种预处理方法最好,这样就很容易对其进行词汇分析和解析。如果您想要Mathematica语言(它的全部语法模块只是一些您想要更改的元素),那么在这种方法中,您是不走运的,因为无论您的更改有多少和“轻量级”,您都需要重新实现几乎完全相同的Mathematica解析器,如果您想让它们可靠地工作,那么只需要进行这些更改。换句话说,我想说的是,我想说的是,要编写一个预处理器,用一些简单或没有语法的类似Lisp的语言生成Mathematica代码,要比尝试对其他标准的mma实现一些语法修改要容易得多。
从技术上讲,编写这样一个预处理程序的方法之一是使用诸如Lex(Flex)和Yacc(Bison)这样的标准工具来定义语法并生成解析器(比如C语言)。这样的解析器可以通过MathLink或LibraryLink (在C中)插入到Mathematica。它的最终结果将是一个字符串,当被解析后,它将成为一个有效的Mathematica表达式。此表达式将表示已解析代码的抽象语法树。例如,这样的代码(这里介绍了Fold的新语法)
"((1|+|{2,3,4,5}))"可以被解析成
"functionCall[fold,{plus,1,{2,3,4,5}}]"这样的预处理器的第二个组件将用Mathematica编写,也许是以基于规则的方式编写,以便从AST生成Mathematica代码。生成的代码必须以某种方式保持未评估。对于上述代码,结果可能如下所示
Hold[Fold[Plus,1,{2,3,4,5}]]如果类似的工具(如Lex(Flex)/Yacc(Bison) )可以在Mathematica中使用(我指的是绑定,它只需要用Mathematica编写代码,然后从它自动生成C解析器,通过MathLink或LibraryLink将其插入内核),这将是最好的。我可能只希望在将来的一些版本中能得到这些资料。缺乏这一点,我所描述的方法将需要大量的低级别工作(如果您愿意的话,可以使用C或Java )。不过,我认为这仍是可行的。如果您可以编写C(或Java),您可以尝试做一些相当简单的语言(在语法/语法方面)--这可能是一个有趣的项目,它将给出一个更复杂的项目的想法。我从一个非常基本的计算器例子开始,也许会把标准的算术运算符改成一些更奇怪的运算子,它们不能正确地解析自身,从而使它更有趣。为了避免MathLink / LibraryLink的复杂性,只需进行测试,您可以使用Run调用得出的可执行文件,将代码作为命令行参数之一传递,并将结果写入一个临时文件,然后将其导入Mathematica。对于计算器的例子,整个事情可以在几个小时内完成。
当然,如果您只想缩写某些长函数名,那么还有一个简单得多的选择--您可以使用With来实现这一点。下面是一个实际的例子--我的彼得·诺维格( Peter )的拼写校正器端口,在这里,我以这种方式作弊,以减少行数:
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-like控件结构,其中硬编码一些最烦人的长mma名称的短名称,然后将其封装在代码块(但是,您将丢失突出显示的代码)。请注意,我通常不提倡这种方法-我这样做只是为了好玩,并减少了一点行数。但至少,这在某种意义上是普遍的,因为它将在互动和一揽子方案中发挥作用。不能做infix操作符,不能更改先例等,但工作几乎为零。
发布于 2011-03-26 01:49:14
不是一个完整的答案,而是为了展示我学到的一个技巧这里 (我认为它更多地与符号重新定义有关,而不是符号):
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-26 11:58:53
(我的第一次回复/邮寄.温柔点)
根据我的经验,该功能似乎有点像一个编程库-de。定义自定义符号的能力似乎在很大程度上取决于使用“符号调色板”来定义和清除每个自定义符号。(“一切都是一种表达”.嗯,除了一些模糊的例子,比如笔记,你必须使用调色板。)真扫兴。
符号包文档明确地提到了这一点,所以我不能抱怨太多。
如果您只想在特定的笔记本中定义自定义的符号,那么注释可能对您很有用。另一方面,如果您的目标是在YourOwnPackage.m中实现自定义符号并将它们分发给其他人,则可能会遇到问题。(除非你对盒子结构非常流利?)
如果有人能纠正我在这一点上的无知,你会让我的月份!)
(我希望使用注释来强制MMA将已订阅的变量视为符号。)
https://stackoverflow.com/questions/5439660
复制相似问题