Mathematica:什么是符号编程?

zen*_*nna 78 haskell programming-languages functional-programming wolfram-mathematica

我是斯蒂芬·沃尔夫勒姆(Stephen Wolfram)的忠实粉丝,但他绝对不会羞于吹响自己的号角.在许多参考文献中,他将Mathematica称为不同的符号编程范例.我不是Mathematica用户.

My questions are: what is this symbolic programming? And how does it compare to functional languages (such as Haskell)?

Yar*_*tov 73

您可以将Mathematica的符号编程视为一个搜索和替换系统,您可以通过指定搜索和替换规则进行编程.

例如,您可以指定以下规则

area := Pi*radius^2;
Run Code Online (Sandbox Code Playgroud)

下次使用时area,它将被替换为Pi*radius^2.现在,假设您定义了新规则

radius:=5
Run Code Online (Sandbox Code Playgroud)

现在,无论何时使用radius,它都会被重写5.如果你评估area它将被重写为Pi*radius^2哪个触发器重写规则radius,你将获得Pi*5^2作为中间结果.这个新表单将触发一个内置的重写规则进行^操作,因此表达式将被进一步重写Pi*25.此时重写停止,因为没有适用的规则.

您可以使用替换规则作为函数来模拟函数式编程.例如,如果要定义添加的函数,则可以执行此操作

add[a_,b_]:=a+b
Run Code Online (Sandbox Code Playgroud)

现在add[x,y]改写成了x+y.如果你想要添加只适用于数字a,b,你可以改为

add[a_?NumericQ, b_?NumericQ] := a + b
Run Code Online (Sandbox Code Playgroud)

现在,add[2,3]重写为2+3使用您的规则然后5使用内置规则+,而add[test1,test2]保持不变.

以下是交互式替换规则的示例

a := ChoiceDialog["Pick one", {1, 2, 3, 4}]
a+1
Run Code Online (Sandbox Code Playgroud)

在这里,a替换为ChoiceDialog,然后被用户在弹出的对话框中选择的数字替换,这使得两个数量都为数字并触发替换规则+.在这里,ChoiceDialog作为一个内置的替换规则,沿着"用户点击的按钮的值替换ChoiceDialog [some stuff]".

可以使用自身需要通过规则重写以生成True或的条件来定义规则False.例如,假设您发明了一种新的方程求解方法,但您认为只有在方法的最终结果为正时才有效.您可以执行以下规则

 solve[x + 5 == b_] := (result = b - 5; result /; result > 0)
Run Code Online (Sandbox Code Playgroud)

在这里,solve[x+5==20]被替换为15,但是solve[x + 5 == -20]没有变化,因为没有适用的规则.阻止此规则应用的条件是/;result>0.Evaluator基本上查看规则应用程序的潜在输出,以决定是否继续使用它.

Mathematica的评估员贪婪地用一个适用于该符号的规则重写每个模式.有时您希望获得更好的控制,在这种情况下,您可以定义自己的规则并像这样手动应用它们

myrules={area->Pi radius^2,radius->5}
area//.myrules
Run Code Online (Sandbox Code Playgroud)

这将应用定义的规则,myrules直到结果停止更改.这与默认评估器非常相似,但现在您可以拥有多组规则并有选择地应用它们.一个更高级的示例显示了如何创建一个类似Prolog的评估器来搜索规则应用程序序列.

当你需要使用Mathematica的默认评估(以利用当前的Mathematica版本的一个缺点大作Integrate,Solve等),想改变评价的默认顺序.这是可能但复杂的,我喜欢认为未来的符号编程实现将有一种更优雅的方式来控制评估序列

  • +1非常好的非旋转无喇叭吹的解释.也许我唯一要补充的是,内核中已经包含了大量规则和算法,代表了大多数语言中几乎所有可用的数学库,然后还有更多. (7认同)
  • Simon,lambda calculus本身只是重写系统之一.术语重写是一种比任何特定TRS更通用的方法. (3认同)
  • @Yaro我觉得当你获得规则作为函数的结果时,事情会变得更有趣(如Solve,DSolve等) (2认同)
  • 我认为这太复杂了,Mathematica程序基本上只是一组替换规则.执行是将现有规则应用于输入直到没有规则匹配的过程 (2认同)

WRe*_*ach 73

当我听到"符号编程"这个短语时,LISP,Prolog和(是的)Mathematica立即跳出脑海.我将符号编程环境描述为用于表示程序文本的表达式也恰好是主要数据结构的环境.结果,在抽象上构建抽象变得非常容易,因为数据可以很容易地转换成代码,反之亦然.

Mathematica大量使用此功能.比LISP和Prolog(恕我直言)更重要.

作为符号编程的示例,请考虑以下事件序列.我有一个CSV文件,如下所示:

r,1,2
g,3,4
Run Code Online (Sandbox Code Playgroud)

我在下面读到了这个文件:

Import["somefile.csv"]
--> {{r,1,2},{g,3,4}}
Run Code Online (Sandbox Code Playgroud)

是结果数据还是代码?这两者都是.它是读取文件产生的数据,但它也恰好是构造该数据的表达式.然而,正如代码所说,这个表达式是惰性的,因为评估它的结果本身就是这样.

所以现在我对结果应用转换:

% /. {c_, x_, y_} :> {c, Disk[{x, y}]}
--> {{r,Disk[{1,2}]},{g,Disk[{3,4}]}}
Run Code Online (Sandbox Code Playgroud)

没有详细说明,所发生的一切都是Disk[{...}]围绕着每条输入线的最后两个数字.结果仍然是数据/代码,但仍然是惰性的.另一个转变:

% /. {"r" -> Red, "g" -> Green}
--> {{Red,Disk[{1,2}]},{Green,Disk[{3,4}]}}
Run Code Online (Sandbox Code Playgroud)

是的,仍然是惰性的.然而,巧合的是,最后的结果恰好是Mathematica内置的特定于图形语言的有效指令列表.最后一次转型,事情开始发生:

% /. x_ :> Graphics[x]
--> Graphics[{{Red,Disk[{1,2}]},{Green,Disk[{3,4}]}}]
Run Code Online (Sandbox Code Playgroud)

实际上,你不会看到最后的结果.在史诗般的语法糖画中,Mathematica会展示红色和绿色圆圈的图片:

替代文字

但乐趣并不止于此.在所有语法糖的下面,我们仍然有一个象征性的表达.我可以应用另一个转换规则:

% /. Red -> Black
Run Code Online (Sandbox Code Playgroud)

替代文字

普雷斯托!红色圆圈变黑了.

正是这种"符号推动"是符号编程的特征.绝大多数Mathematica编程具有这种性质.

功能与象征

我不会详细讨论符号和函数式编程之间的差异,但我将提供一些评论.

人们可以将符号编程视为问题的答案:"如果我只使用表达式转换来模拟所有内容,会发生什么?" 相比之下,功能编程可以被视为一种答案:"如果我只使用函数来模拟所有内容,会发生什么?" 就像符号编程一样,函数式编程可以很容易地快速构建抽象层.我在这里给出的例子很容易在Haskell中使用功能性反应动画方法再现.函数式编程是关于函数组合,更高级函数,组合器 - 所有可以用函数做的漂亮事情.

Mathematica显然针对符号编程进行了优化.可以用功能样式编写代码,但Mathematica中的功能特性实际上只是转换的薄外壳(以及漏洞抽象,请参见下面的脚注).

Haskell明显针对函数式编程进行了优化.可以用符号样式编写代码,但我会狡辩说程序和数据的语法表示是完全不同的,使得体验不是最理想的.

结束语

总之,我主张功能编程(由Haskell代表)和符号编程(由Mathematica代表)之间存在区别.我认为,如果一个人同时研究,那么人们将学到的东西远远超过仅研究一个 - 对于清晰度的最终考验.


Mathematica中的漏功能抽象?

是的,漏水了.试试这个,例如:

f[x_] := g[Function[a, x]];
g[fn_] := Module[{h}, h[a_] := fn[a]; h[0]];
f[999]
Run Code Online (Sandbox Code Playgroud)

正式向世界资源研究所报告并承认.回应:避免使用Function[var, body](Function[body]没关系).

  • @Simon:是的,我收到了来自WRI的电子邮件,声明如果我担心函数的语义会根据"调用链"中的任何调用者是否恰好使用类似名称的符号而改变,那么我应该避免使用`Function [var,body]`.没有解释为什么这不能解决,但我推测,因为`功能'自1.0以来一直存在,所以在游戏后期更改其行为将是灾难性的.该问题在(稍微)更详细的描述[这里](http://weaklyreachable.blogspot.com/2007/06/mathematica-pure-function-scope-problem_2182.html)中描述. (6认同)
  • 由于其内部的暴露程度在mma中,我甚至不确定`Function`是否可以治愈,即使在原则上 - 至少使用当前入侵的`Rule`和`RuleDelayed`的语义,它们不尊重内部范围构造'绑定,*包括自己*.在我看来,这种现象与`Rule`和`RuleDelayed`的这个属性有关,而不是与`Function`有关.但不管怎样,我同意改变这一点现在非常危险.太糟糕了,因为不应该使用`函数[var,body]` - 这样的错误几乎不可能在大型项目中捕获. (5认同)
  • WRI真的建议你避免使用`Function [var,body]`吗?这很奇怪,因为它在文档中被推荐...... (2认同)

Mic*_*ohl 9

正如其他人已经提到的那样,Mathematica做了很多术语重写.也许Haskell不是最好的比较,但Pure是一个很好的功能性术语重写语言(对于具有Haskell背景的人来说应该感觉熟悉).也许在学期改写上阅读他们的Wiki页面会为你清理一些事情:

http://code.google.com/p/pure-lang/wiki/Rewriting


SK-*_*gic 6

Mathematica正在大量使用术语重写.该语言为各种形式的重写提供了特殊的语法,特别支持规则和策略.范式不是那种"新",当然它并不是唯一的,但它们肯定处于这种"象征性编程"的前沿,与其他强大的玩家如Axiom一起.

至于与Haskell的比较,那么你可以在那里重写一下,从你的样板库中删除一些帮助,但它并不像在动态类型的Mathematica中那么容易.