0
votes

Let say I have some types

type A = { ... }

type B = { ... }

type AB = A of A | B of B

type Ainfo = { //some additional information about A
    ... 
}

type Binfo = { //some additional information about B
    ... 
}

type ABinfo = Ainfo of Ainfo | Binfo of Binfo

and there is a function which works with these types - it accepts 'entity' which can be A or B plus some additional information about this entity.

let myFunc (entity: AB) (info: ABinfo) = ...

How can I enforce complier restrictions to avoid cases when 'myFunc' is called with entity A and info Binfo and vice versa?

PS this question relates to my other question Extend type in F#

1
What should happen if you try to pass A together with Binfo? I know you're going to say "it shouldn't compile", but then my next question is: what if you don't even know what you're passing at the time of writing the program? Suppose, for example, that the two parameters of the function ultimately come from the user input. In this case, you cannot know what they will be until the user inputs them. So what should happen if the user inputs a wrong combination? - Fyodor Soikin
@FyodorSoikin in that case there will be an exception - irriss
Well, if you're ok with an exception, then just have your function check if the inputs match and throw an exception if they don't. - Fyodor Soikin

1 Answers

3
votes

Your question is too generic. I suspect that it is an instance of the XY problem. You have some concrete situation and your question assumes that being able to enforce such compiler restriction would give you the answer. There is no easy way to do this and I suspect the answer to your actual question is that you need to design your types differently. However, it is not possible to say how without knowing more about your actual scenario and what the types represent.

If you really want to write a function that can take only either A with AInfo or B with BInfo, then you can do this by definining a new discriminated union type:

type ABplus = 
  | AwithInfo of A * Ainfo
  | BwithInfo of B * Binfo

let myFunc ab = 
  match ab with
  | AwithInfo(a, ainfo) -> ...
  | BwithInfo(b, Binfo) -> ...