问题描述
我是斯蒂芬·沃尔夫勒姆的忠实粉丝,但他绝对不会害羞。在许多参考文献中,他将Mathematica作为一种不同的符号编程范例来颂扬。我不是Mathematica用户。我的问题是:这是什么符号编程?它与功能性语言(如Haskell)相比如何?
您可以将Mathematica的符号编程视为一种搜索 - 并通过指定搜索和替换规则来进行编程。
例如,您可以指定以下规则:
area:= PI *半径^ 2;
下次您使用区域
时,将被替换为 Pi * radius ^ 2
。现在,假设你定义了新规则
radius:= 5
现在,无论何时使用 radius
,它都会被重写为 5
。如果您评估区域
,它会被重写为 Pi * radius ^ 2
,这会触发<$ c $的重写规则c> radius ,你会得到 Pi * 5 ^ 2
作为中间结果。这个新表单将触发 ^
操作的内置重写规则,因此表达式将被进一步重写为 Pi * 25
。此时重写会停止,因为没有适用的规则。
您可以使用替换规则作为函数来模拟函数式编程。例如,如果你想定义一个添加的函数,你可以这样做:
pre $ add $ [a_,b _]:= a + b
现在 add [x,y]
被重写为 x + y
。如果你想添加只适用于数字a,b,你可以做
add [a_?NumericQ,b_?NumericQ ]:= a + b
现在, add [2,3]
使用您的规则重写为 2 + 3
,然后使用内置规则将其重写为 5
+
,而 add [test1,test2]
保持不变。
下面是一个交互替换规则的例子
a:= ChoiceDialog [Pick one,{1,2 ,3,4}]
a + 1
这里,一个
被替换为 ChoiceDialog
,然后用用户在弹出的对话框中选择的数字替换它,这使得数字和触发器替换规则为 +
。在这里, ChoiceDialog
作为内置替换规则,沿着将ChoiceDialog [某些东西]替换为用户点击的按钮的值。
$ b
可以使用自己需要通过规则重写的条件来定义规则,以产生 True
或 False
。例如,假设你发明了一个新的方程求解方法,但是你认为只有当你的方法的最终结果是肯定的时,它才有效。您可以执行以下规则:
$ p $ solve [x + 5 == b_]:=(result = b - 5; result / ; result> 0)
这里, solve [x + 5 == 20]
被替换为15,但是 solve [x + 5 == -20]
没有变化,因为没有适用的规则。阻止应用此规则的条件是 /; result> 0
。评估者从本质上看待规则应用程序的潜在输出,以决定是否继续使用它。
Mathematica的评估者贪婪地用适用于该符号的规则之一重写每个模式。有时你想要更好的控制,在这种情况下,你可以定义自己的规则并像这样手动应用它们。
myrules = {area-> Pi radius ^ 2,radius-> 5}
area //。myrules
这将应用 myrules
中定义的规则,直到结果停止更改。这与默认评估程序非常相似,但现在可以有多组规则并选择性地应用它们。更高级的显示了如何创建一个类似Prolog的评估程序,以便在规则应用程序。
当您需要使用Mathematica的默认评估程序(以利用 Integrate ,
解决
等)和想要更改默认的评估顺序。这是可能的,但,我喜欢认为一些未来的符号编程实现将会有一个更优雅的方式来控制评估序列
I am a big fan of Stephen Wolfram, but he is definitely one not shy of tooting his own horn. In many references, he extols Mathematica as a different symbolic programming paradigm. I am not a Mathematica user.
My questions are: what is this symbolic programming? And how does it compare to functional languages (such as Haskell)?
解决方案
You can think of Mathematica's symbolic programming as a search-and-replace system where you program by specifying search-and-replace rules.
For instance you could specify the following rule
area := Pi*radius^2;
Next time you use
area
, it'll be replaced with Pi*radius^2
. Now, suppose you define new rule
radius:=5
Now, whenever you use
radius
, it'll get rewritten into 5
. If you evaluate area
it'll get rewritten into Pi*radius^2
which triggers rewriting rule for radius
and you'll get Pi*5^2
as an intermediate result. This new form will trigger a built-in rewriting rule for ^
operation so the expression will get further rewritten into Pi*25
. At this point rewriting stops because there are no applicable rules.
You can emulate functional programming by using your replacement rules as function. For instance, if you want to define a function that adds, you could do
add[a_,b_]:=a+b
Now
add[x,y]
gets rewritten into x+y
. If you want add to only apply for numeric a,b, you could instead do
add[a_?NumericQ, b_?NumericQ] := a + b
Now,
add[2,3]
gets rewritten into 2+3
using your rule and then into 5
using built-in rule for +
, whereas add[test1,test2]
remains unchanged.
Here's an example of an interactive replacement rule
a := ChoiceDialog["Pick one", {1, 2, 3, 4}]
a+1
Here,
a
gets replaced with ChoiceDialog
, which then gets replaced with the number the user chose on the dialog that popped up, which makes both quantities numeric and triggers replacement rule for +
. Here, ChoiceDialog
as a built-in replacement rule along the lines of "replace ChoiceDialog[some stuff] with the value of button the user clicked".
Rules can be defined using conditions which themselves need to go through rule-rewriting in order to produce
True
or False
. For instance suppose you invented a new equation solving method, but you think it only works when the final result of your method is positive. You could do the following rule
solve[x + 5 == b_] := (result = b - 5; result /; result > 0)
Here,
solve[x+5==20]
gets replaced with 15, but solve[x + 5 == -20]
is unchanged because there's no rule that applies. The condition that prevents this rule from applying is /;result>0
. Evaluator essentially looks the potential output of rule application to decide whether to go ahead with it.
Mathematica's evaluator greedily rewrites every pattern with one of the rules that apply for that symbol. Sometimes you want to have finer control, and in such case you could define your own rules and apply them manually like this
myrules={area->Pi radius^2,radius->5}
area//.myrules
This will apply rules defined in
myrules
until result stops changing. This is pretty similar to the default evaluator, but now you could have several sets of rules and apply them selectively. A more advanced example shows how to make a Prolog-like evaluator that searches over sequences of rule applications.
One drawback of current Mathematica version comes up when you need to use Mathematica's default evaluator (to make use of
Integrate
, Solve
, etc) and want to change default sequence of evaluation. That is possible but complicated, and I like to think that some future implementation of symbolic programming will have a more elegant way of controlling evaluation sequence
这篇关于Mathematica:什么是符号编程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!