December 2007 - Posts

Tuples: an F# lightweight data structure

Maybe the best thing to do is to start by showing a few examples of tuples:

let amigo = ("Sebastián", 7)

let pair1 = (3, 2)

let pair2 = (2, 5)

let student = "Santiago", "Monterrey", 2007, true

The first tuple ("Sebastián", 7) groups two values: a string and an integer, allowing us to handle them as just one thing, this "thing" has the type string * int, that is, it belongs to the set of all the combinations of strings and integers, in this sense ("Sebastián", 7) has the same type of ("Alejandra", 19). By the way, note how we separate the different elements of the tuple with commas.

Tuples pair1 and pair2 are of type (make a wild guess...) int * int. Strictly speaking, "let pair1 = (3, 2)" defines a function pair1 that always returns the same tuple (3, 2), that is, it's a constant function that takes 0 parameters.

Finally, the student tuple is of type string * string * int * bool, the fact that I have omitted the parenthesis is not a mistake, tuples actually don't need them and many F# programmers don't put them (even though, I personally prefer to write them down, to remind myself that what I am seeing is something to be treated as a whole).

With these tuples in our hands, we can define some functions:

let addPairs (x1,y1) (x2, y2) = x1 + x2, y1 + y2

 

let primero (p, q) = p

 

let getYear (name, city, year, status) = year

 

let getYearFunny (_, _, year, _) = year

 

addPairs is a function that receives two tuples and returns another (to be precise, its type is int * int -> int * int -> int * int). Just to get used to it, I omitted the parenthesis in the function body (but I insist: I don't think it's a good idea).

The function primero is even more interesting: its type is... 'a * 'b -> 'a, which means that it receives a tuple containing some stuff and some other stuff and returns something of the same type of the first stuff. Maybe we expected the type to be something like int * int -> int, but that would have unnecessarily limited the usability of the function. For example, we can now say "primero amigo" and get the string "Santiago" or "primero pair1" and get the integer 3. If you think about it, the use of 'a and 'b is very similar to the use of generics in C# or VB.NET. It's utterly important to note that primero does *not* receive two parameters p and q but just one parameter, namely a two-value tuple, and then the function body tells that what must be returned is the first of those two values, this is a simple example of F# pattern matching. By the way, it's really not necessary to write the primero function, because F# already provides us with fst and snd.

A somewhat more complex example of pattern matching is getYear, which gets a tuple of type 'a * 'b * 'c * 'd and returns a 'c. "getYear student" of course returns 2007 (what is returned by getYear ("William", "Jones", 1706,  3.1416)? Is this even possible?). It's interesting to note that even though in getYear definition we name the four elements of the tuple, we use just one of them, which takes us to the definition of getYearFunny: the "_" symbol (underscore) basically means "an element whose value I don't care about", and so getYearFunny ignores the first, second, and fourth values in the tuple. This is our first encounter with this "_" guy and we'll find out that it appears frequently and that it's very useful when doing pattern matching.

Finally, let's mention a few more characteristics and uses of tuples:

  1. A tuple have a fixed number of elements: be them two, three or thirty, once set you can't add or remove elements from a tuple
  2. The elements in a tuple doesn't have a name, you access them by their position in the tuple with the help of pattern matching
  3. It's almost redundant to say, but a tuple may contain other tuples, e.g. what's the value of fst (snd ("Santiago" (9, 10))) ? Do we need all the parenthesis?
  4. A tuple is a handy way of making a function return multiple values (as the original getYear does) or to pass multiple values to a function that expects only one parameter

Tuples are a basic and simple component of F#, built to represent a fixed-size sequential set of values.

F# doesn't need parenthesis in functions, or does it?

In a previous posting I mentioned that when you define a function in F# you don't need parenthesis surrounding the parameters, or commas separating them. So, this simple definitions are all valid:

let negate a = -a

 

let add a b = a + b

 

let multiply a b = a * b

When you compile them, you get this messages:

image

negate is a function that takes an integer and returns an integer, add takes two integers and return another, etc.

Now we can type "add 3 4" and we get a 7, but things get interesting if we try to negate the "add 3 4":

image

Why? To solve this mystery we have to understand that function application (i.e. invocation or calling) is an operation as well as +, *, or -. As other operations, application has a precedence (which operation is called first when you've got a mixture) and associativity (if you have "a + b + c", does this mean "(a + b) + c" or "a + (b + c)"). In F# function application has the highest precedence and it is left associative, so that

negate add 3 4

is interpreted as "(negate add) 3 4" and not as "negate (add 3 4)". It pops to the eye that "(negate add)" can't be right, but this is not because you can't pass a function as parameter in F# (which is not only possible but common and pretty useful) but because negate expects an integer as parameter and add is a function, not a number. Maybe the compiler message could be more explicit, but I hope the real source of the problem is more clear now. So, in order for F# to evaluate the expression in the expected order we should write:

negate (add 3 4)

And now, F# first adds 3 and 4, giving 7, and then negates the result giving -7. There are several other scenarios where for getting F# to do the evaluation in the adequate order we must use parenthesis, but remember you will be using them not because invocation requires them but because of precedence and associativity. After this discussion, I think it will be easier to understand the following results:

image

Maybe the only unexpected expression is the last "(-1)", once again the parenthesis are there because "-" is an operator and without them, the expression would be interpreted as "(multiply 3 -) 1", and the compiler will shout because multiply expects two numbers and "-" is a function, not a number. This could be surprising at first (I bumped onto this very same issue with Haskell several years ago) but once you know why, it's not really a problem.

Posted by Edgar Sánchez with 1 comment(s)

Word 2007 and Microsoft Math

Reading Alfred Thompson blog, who focus on computer science teaching at K-12 schools (what we call in Ecuador basic high school), I found this nice entry: Microsoft released a few days ago the Word 2007 Math Add-in. After installing and playing with it for just 2 minutes, I was able to create this document:

As you can see, the add-in lets you put formulas inside the text (including fractions, exponentials, sigmas, integrals, etc.), create graphs from an equation (I just typed in y = ...), and even solve those equations. Ah, this is the kind of stuff I would've loved to have at high school or college.

Speaking of which, the add-in seems to be based (I'm just especulating here) on Microsoft Math, an unexpensive stand alone product I wasn't aware of, that could be a nice present for a high school niece in love with physics or math.

Posted by Edgar Sánchez with 1 comment(s)
Filed under: ,
More Posts