Jackson Tale
Jackson Tale

Reputation: 25842

Is it possible to make this fully polymorphic in OCaml?

in OCaml

    let nth_diff_type i (x, y, z) =
        match i with
         1 -> x
        |2 -> y
        |3 -> z
        |_ -> raise (Invalid_argument "nth")

So the current type is int->('a,'a,'a)->'a, right?

It implies that x, y, z must have the same type.

So my question is that is it possible to give it maximum polymorphic, so that x, y, z don't need to have the same type?

Upvotes: 4

Views: 146

Answers (3)

didierc
didierc

Reputation: 14750

If your function were to apply an arbitrary function f to an arbitrary element of a tuple such as the function f has the right type, then you could make this polymorphic to some extend.

In other words, if you think about what you may do with your function, you'll come up with the conclusion that you will need a function of the right type to apply it to the result of nth_diff_type, whatever that type may be.

If we suppose for an instant that nth_diff_type works with any tuple, its result is potentially any type. You might get an int, a string, or instances of more complex datatypes. Let's call that type t. Then what can you do with a value of type t? You may only pass it to a function which accepts values of t.

So the problem now is to select the proper function, and that selection certainly will be done on very similar criteria than the rank of the element within your tuple. If it is so, why not simply pass your tuple, and a tuple of the functions which could be applied to nth_diff_type , and let it do the application by itself?

let nth_diff_type i (a,b,c) (fa,fb,fc) =
    match i with
        | 1 -> fa a
        | 2 -> fb b
        | 3 -> fc c
        | _  -> failwith "out of range"

-: val nth_diff_type : int -> ( 'a * 'b * 'c) -> (('a -> 'd) * ('b -> 'd) * ('c -> 'd)) -> 'd

Upvotes: 2

gasche
gasche

Reputation: 31469

The code is already fully-polymorphic in non-dependent type systems. You could move to a dependent type system (but you probably don't want, because of the complexity costs), where the type would be something like:

(n : int) -> (a * b * c) -> (match n with 1 -> a | 2 -> b | 3 -> c | _ -> Error)

Besides pad suggestion, you may also want to use a record or object type to have a direct "out projection" operation instead of having to define it by pattern-matching first.

type ('a, 'b, 'c) triple = { nth1 : 'a; nth2 : 'b; nth3 : 'c } 

(* replace *) nth_diff_type 2 v (* by *) v.nth2

With an object type (which adds a structural flavor of not having to define the type beforehand)

 (* replace *) nth_diff_type 2 v (* by *) v#nth2

Note that these replacement only work with constant integers (because otherwise you need an integer->type dependency). You could work out something with GADTs and existential types to support passing the particular choice around, but you will have to pay a huge complexity cost for something that is more likely a result of not being familiar enough with the existing simple type system to understand how you really want to do things.

Upvotes: 1

pad
pad

Reputation: 41290

No, it isn't.

A function in OCaml should have only one return type. You can have different argument types if your return type is unique:

let nth_diff_type i (x, y, z) =
    match i with
    | 1 -> `Fst x
    | 2 -> `Snd y
    | 3 -> `Thd z
    |_ -> raise (Invalid_argument "nth")

// val nth_diff_type :
//   int -> 'a * 'b * 'c -> [> `Fst of 'a | `Snd of 'b | `Thd of 'c ] = <fun>

If you would like to create a few utility functions for triplets, unfortunately you have to define them separately:

let fst3 (x, _, _) = x
let snd3 (_, y, _) = y
let thd3 (_, _, z) = z

Upvotes: 8

Related Questions