Reputation: 43
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
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