Wednesday 5 December 2007

SML/CAML/F# differences

It's all Nick Benton's fault! I just spent a whole day trying to get some of his cool "embedded interpreters" code through F#. Ug. It was very hard to pin this down, but it turned out to be a difference between SML (the language I know and Nick's code is written in) and CAML/F#.

Here's the offending function:

let mypair args =
match args with
((e,p),(e',p')) -> (function (x,y) -> (e x)@(e' y), function [x;y] -> (p x, p' y))

Type this into F# you get the following type:

val mypair : (('a -> 'b list) * ('c -> 'd)) * (('e -> 'b list) * ('c -> 'f)) -> ('a * 'e -> 'b list * ('c list -> 'd * 'f))

Type the similar code into SML/NJ you get the following type:

val it = fn : (('a -> 'b list) * ('c -> 'd)) * (('e -> 'b list) * ('c -> 'f)) -> ('a * 'e -> 'b list) * ('c list -> 'd * 'f)

Looks the same, right? But no. I'd forgotten that CAML treats pairs differently (as you can drop the brackets). What I had meant to write was this:

let mypair args =
match args with
((e,p),(e',p')) -> ((function (x,y) -> (e x)@(e' y)), (function [x;y] -> (p x, p' y)))

[Spot the new pair of brackets!]. Interesting F# claims the type is:

val mypair : (('a -> 'b list) * ('c -> 'd)) * (('e -> 'b list) * ('c -> 'f)) -> ('a * 'e -> 'b list) * ('c list -> 'd * 'f)

Look carefully you'll see the different bracketting. Clearly I still have more SML to forget!

No comments: