OCaml unexpected type mismatch in tuples
Asked Answered
A

2

7

I'm trying to write a function, that takes an integer and a triplet and returns an element of the triplet at the given position (exercise 5.3 from Hickey's book). Triplet should be able to contain elements of different types.

I thought, that if I write 3 little functions, each returning a specific element of the triple and make my big function return one of them accordingly, then it would do the trick, but it doesn't work.

I've tried to fiddle with this "eta-expansion" concept, but I didn't get it.

let nth1 (a, _, _) = a
let nth2 (_, b, _) = b
let nth3 (_, _, c) = c

let nth i = match i with
    | 1 -> nth1
    | 2 -> nth2
    | _ -> nth3

let main = printf "%d\n" (nth 1 ("hello", 2, 'c'))

So it should just write "2" here. Any advice?

Amazement answered 2/10, 2012 at 17:36 Comment(1)
Editing because this is not really the value restriction, calling it such will confuse readers.Island
I
7

The basic answer to your question:

In OCaml, the way the type system works will force nth to return only a single type. What you want is something resembling an intersection type, but the static type semantics for OCaml will instead force nth to return only a single type. The upshot of this is that your tuple must degenerate into the case where element is the same type.

Let's consider this interaction:

# let nth1 (a,_,_) =a;;
val nth1 : 'a * 'b * 'c -> 'a = <fun>
# let nth2 (_,b,_) = b;;
val nth2 : 'a * 'b * 'c -> 'b = <fun>
# let nth3 (_,_,c) = c;;
val nth3 : 'a * 'b * 'c -> 'c = <fun>
# let nth i = match i with
      | 1 -> nth1
      | 2 -> nth2
      | _ -> nth3;;
val nth : int -> 'a * 'a * 'a -> 'a = <fun>

So your question is strange, not because of the printf call, but instead, because of the definition of nth. Instead you might look into making a unique type which is the combination of a few of these types.

Indeed, the kind of behavior you describe feels a little bit like dependent types, where the type you get actually depends on the value of the input i. This should naturally be problematic, as dependent typing is much more expressive than the let bound polymorphism seen in ML!

I will say, that you can do this for instances of tuples, for example, you can make a type:

type IntOrStringOrX = int | string | X

and then you can correspondingly write down a type of nth...

Island answered 2/10, 2012 at 17:47 Comment(4)
Thank you for your help. I'll definitely look at types and instances later... It's just wierd that this question came up before the actual chapter on them.Amazement
@user1714986: interesting.. can you point me at the relevant example in the book, it's contrived as to do it properly would require the use of an elaborate typing system ocaml does not have.Island
Yes, the book is called Introduction to Objective Caml by J. Hickey (online link courses.cms.caltech.edu/cs134/cs134b/book.pdf) exercise 5.3. The theory part is the first two paragraphs of chapter 5.Amazement
@Amazement ah yes, I believe the point of the exercise, along with Jeffrey, may be to show you why lists in OCaml are defined as homogeneously typed!Island
P
6

It usually helps to think about types before writing code. What is the proposed type of your function?

Presurmise answered 2/10, 2012 at 17:47 Comment(2)
Well, I got something like "int -> ((abc) -> (a OR b OR c))", which is obviously wrong... Thanks for exposing the error!Amazement
I assume this is the point of the exercise. A little sneaky maybe, but good.Presurmise

© 2022 - 2024 — McMap. All rights reserved.