3
votes

I have code that looks something like

type U0 = E1|E2|E3...
type T2 = {field1: string; field2: string; field3: string}
type T1 = T2*T2*T2
type T0 = T1*T1*T1

And I want to enforce some predicate P1 on the type of field1 that field1 such that (GetUnionCases typeof<U0>).contains(field1). I hope that isn't too abstract.

So to do this, I'd like to introduce the type P1, with a definition something like

type P1(x) = (GetUnionCases typeof<U0>).map(fun x -> x.Name).contains(x)
1
You may consider playing with protection levels combined with a named constructor, just like in this answer. - bytebuster

1 Answers

2
votes

In general, F# does not have any form of refinement types that would let you attach arbitrary predicates as constraints to type declarations.

It is difficult to give a more specific answer based on your somewhat abstract example, but very often, it is possible to design the domain (your types) differently, so that the predicate is enforced by construction - in other words, design your types so that any value of the type automatically satisfies the predicate. The designing with types article series has some practical examples showing that.

I do not fully follow your example, but say you want to make sure that the string of field1 contains the value E1, the string field2 contains the value E2 (as a sub-string) and so on. So:

{  field1 = "hi E1 there" } // valid
{  field1 = "hi there" } // invalid

You could change the type of field1 from string to string * string representing the prefix and the suffix of the string "E1" and so you would be only able to construct:

{ field1 = "hi", "there" } // valid

There is now no way to create a value that does not implicitly have "E1" as a sub-string!
I'm pretty sure I misunderstood your example, but I hope this demonstrates the idea...