5

John Fremlin's blog: Subverting the OCaml type system

 3 years ago
source link: http://john.freml.in/struggles-with-ocaml
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Posted 2009-09-02 12:13:00 GMT

I had a program that generated a report of a few interesting numerical results from an experiment (number of packets lost, number of packets received, mean latency, etc.). These statistics might have a high variance or might be very tightly distributed. To investigate, I ran multiple experiments with the same parameters. Now I wanted to generate a summary table with some statistics on the per experiment statistics (maximum packets lost across all runs, etc.).

One small polish on the obvious design is that the summary program should calculate and output the latency statistics in floating point format but the maximum of the packets lost is clearly an integer, and should be output as such.

In OCaml, we can define a union datatype that allows for both types of values or an undefined value.

type num = I of int | F of float | N;;

How about taking the maximum of a pair of nums? The max function (and at a lower level the > function) can be applied to a pair of ints or a pair of floats. You might think that this would work

let lift2broken f x y =
  match (x,y) with
    | (I i) ,(I j) -> I (f i  j)
    | (F i), (F j) -> F (f i  j);;

Then to convert the max function to something that would work on nums, you would do (lift2broken max). But lift2broken does not compile: Error: This expression has type float but an expression was expected of type int.

The problem is that the type of max (and of f) is 'a -> 'a -> 'a, but on encountering the first use of f, i.e. I (f i j), the unspecified type 'a is unified with int.

Adrien Pierard helped me to this solution

let lift2if f_I f_F  x y =
  match (x,y) with
    | (I i) ,(I j) -> I (f_I i  j)
    | (F i), (F j) -> F (f_F i  j);;
 
let lift2 f =
  let fi = f
  and ff = Obj.magic f
  in lift2if fi ff;;

In some ways, it seems very unfortunate that something as simple as this requires one to break out of the type system with Obj.magic, and shows a crack in the illusion that functions with variable types are really functions . . . I'm very new to the language and I wonder if there isn't a better way to do it? Presumably there are ML dialects where this issue is finessed?

Here is the complete program.

Sorry for the unrelated comment , but I really like your blog design. It's very refreshing to come across a blog with decent font size and simple design!

Posted 2009-09-03 23:27:52 GMT by Anonymous

hmm... you need ad hoc polymorphism which standard ML doesn't provide. Obj.magic indeed looks like a veeeery ad hoc magic. :)

Posted 2009-09-08 00:17:03 GMT by Jianshi Huang

I had the same issue but wasn't aware of this trick, thanks!

Posted 2010-03-28 17:27:08 GMT by Anonymous

Post a comment


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK