My computational biology class requires us to use Mathematica. I'm not very familiar with it yet, but I've discovered a couple basic design flaws that make me extremely uneasy using it.
Mathematica makes no syntactic distinction between symbols and variables. For example, if I want a function named Foo to return the symbol "NA" when attempting to divide by zero, I can just write:
Foo[x_, y_] := If[y == 0, NA, x/y]
This works as long as NA doesn't have a value assigned to it. However if NA were to be set to, say, 3, then the function would just return 3. The same behavior causes problems if you try to use the "/." operator as if it's like a where clause in Haskell. For example, the following will return x+1 as long as q doesn't already have a value:
Add1[x_] := x + q /. q -> 1
But if q were to be set to 4, then Add1[2] would return 6. Sigh.
And while I'm at it, what's up with requiring underscores for the formal parameter list of a function? If you omit the underscore, you get some really weird behavior. Consider the following function definition:
Foo[qwerty] := 5
If qwerty doesn't have a value yet, then this function will return the value 5 if and only if you pass it the symbol "qwerty". However, suppose qwerty had the value 9. Then the function will return 5 if and only if you pass 9. Now for the kicker: suppose qwerty was undefined when the function was defined, but someone assigned a value to qwerty at some point later on. Now the expression "Foo[qwerty]" will fail, and just return "Foo[qwerty]". Gah!
I'm not a careful enough programmer to be able to deal with this kind of crazyness. Especially in the absence of lexical scoping. I officially hate this language (opinion subject to change should I receive a lobotomy at some point in the future).
Posted on October 11, 2006 08:43 PM
More languages articles
Mathematica is bizarre, but there is method to the madness. For help with your local variable woes, heck out "Scoping" in the online documentation:
http://documents.wolfram.com/mathematica/Built-inFunctions/Programming/Scoping/index.en.html
I don't know if there's anything you can do about your NA example, but in the second one you can guarantee that q is unbound by using Module.
The underscores for formal parameters reflect the fact that they're not really formal parameters as we are accustomed to using in other languages. Mathematica uses lisp-inspired tree structures to represent all expressions, but they are evaluated using a pattern matcher (something along the lines of Prolog). Underscores are used to introduce variables ("blanks") in the patterns; these blanks can be named (just like we might refer to bits of matched pattern in regular expression substitutions) giving the illusion of formal parameters. You can also put on qualifiers to ensure that the blank only matches a pattern satisfying some predicate by putting the predicate after the underscore.
Overall I find the syntax dissatisfying (at least it never *looks* pretty; they adopted Lisp-like expressions but no Lisp-like indentation standards) but it can be fun once you figure out how it works.
Here are a few of my own ponderings while learning Mathematica: http://nibot-lab.livejournal.com/tag/mathematica
Posted by: Tobin Fricke at October 11, 2006 10:14 PMI think the rationale behind Mathematica's syntax was that they wanted to use Lisp, but hide the Lispiness of it as much as possible. They really go out of their way to avoid () parentheses if at all possible.
Posted by: crzwdjk at October 11, 2006 10:20 PMUse Block or Module to localize variables and protect against non localized variables from elsewhere.
If you want to work with global variables in a session, then you can prevent them being assigned values later in the session (or from values being changed or cleared) with Protect.
Posted by: Jon at October 27, 2006 12:40 PM