Search code examples
programming-languageshaskellfunctional-programmingwolfram-mathematica

Mathematica: what is symbolic programming?


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)?


Solution

  • 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