user1559410
user1559410

Reputation: 43

Can the F# type system do this?

I have a lot of various types that have a common purpose, but little else in common. For the sake of explanation, they might as well be along the lines of:

type blah<'a> = Blah of 'a

type huha<'a> = Huha of 'a

I often need to repeat a large chunk of boilerplate that could go inside a function along the lines of:

let f (x:something<int>) (g:something<char> -> float) : float =

But that would require somehow enforcing that the two somethings in the type are the same. In other words, I would like to be able to call the function f as:

f (Blah 1) (fun (b:blah<float>) -> .... )
f (Huha 1) (fun (b:huha<float>) -> .... )

Obviously, a trivial solution is to create a discriminated union of all the types function f could possibly take, and make every g (i.e. f's second argument) check it got whatever type it expected. But that means having a massive type that causes the universe to recompile every time anything changes, and it's not like checking types at runtime helps a great deal either.

So, can someone please see a way of doing what I want in a typesafe way? Many thanks.

Upvotes: 4

Views: 353

Answers (1)

wmeyer
wmeyer

Reputation: 3496

As far as I understand, you cannot do this directly in F#.

But maybe operator overloading will help. You would have to implement f for every type, though. But maybe you can delegate to a common implementation.

A code example for operator overloading, ensuring the right types:

type T<'a> =
   | T of 'a
   static member (.+.) (l:T<int>, r:T<char> -> float) = 42.0

type U<'a> =
   | U of 'a
   static member (.+.) (l:U<int>, r:U<char> -> float) = 13.1


let ft (t:T<char>) = 42.0

let fu (t:U<char>) = 42.0

let t = T 42 .+. ft
let u = U 13 .+. fu

// does not compile:
let wrong = T 42 .+. fu

Upvotes: 2

Related Questions