More than most, what impresses me about ML is that it isn't a Pie in the Sky language but rather a Down and Dirty language designed to be heavily used. Using Patterns in your function definitions as a shortcut feels much natural than I thought it would at first. In fact, it was the first thing I remarked about the language. Last year I noted to my good friend dnm that function definition in ML looked a lot like a theorem proof. Dan informed that it's because ML was first designed to prove theorems.
Although, I'm still a little confused as to how to tell the difference between a tuple and a simple parenthesed type. Let me explain: In ML, as in a lot (most?) of functional languages, the type of a tuple changes with it's number of elements. (This might be pretty tough to grasp if you've only had experience with procedural and/or object-oriented languages) Here I'm going to take a tuple and request the first element from it (that's what #1 does when applied to a tuple):
#1(1,2,3); val it = 1 : int #1(1,2); val it = 1 : intSimple so far. Now to get that first element.
#1(1); stdIn:29.1-29.6 Error: operator and operand don't agree [literal] operator domain: {1:'Y; 'Z} operand: int in expression: (fn {1=1,...} => 1) 1D'oh! So how am I supposed to get the first element of this faux tuple? I actually agonized over this for about 2 whole minutes on the train last week.(I'm waking up really early now, cut me some slack. Not to mention the fact that I don't have an ML interpreter with me on the train, I only have a faulty simulation of a ML interpreter; my brain). Aha! Just evaluate it!
(1); val it = 1 : intta da. Next time: Strong Type Systems have met their match; type inference in ML is as smooth as a sex-ay lad-ay.
# — 05 March, 2003