问题
Here is my problem:
let foo =
match bar with
| barConfig1 -> configType1(devices:DeviceEntities,DeviceStartIndex,inputStartIndex,outputStartIndex)
| barConfig2 -> configType2(devices:DeviceEntities,DeviceStartIndex,inputStartIndex,outputStartIndex)
| barConfig3 -> configType3(devices:DeviceEntities,DeviceStartIndex,inputStartIndex,outputStartIndex)
| barConfig4 -> configType4(devices:DeviceEntities,DeviceStartIndex,inputStartIndex,outputStartIndex)
I'd like to have the type of foo be determined by the match statement, but it always sets foo to the first type.
type bar =
|barConfig1
|barConfig2
|barConfig3
|barConfig4
回答1:
In F#, there are no statements, only expressions, and each expression has to have a single concrete type. A match
block is an expression as well, meaning that it has to have a single concrete type. What follows from that is that each case of the match has to have the same type as well.
That is, something like this is not valid F#:
let foo = // int? string?
match bar with // int? string?
| Int -> 3 // int
| String -> "Three" // string
In this case, the type inference mechanism will expect the type of the match to be the same as the type of the first case - int, and end up confused when it sees the string in the second. In your example the same thing happens - type inference expects all the cases to return a configType1.
A way around it would be by casting the values into a common supertype or interface type. So for your case, assuming the configTypes implement a common IConfigType interface:
let foo = // IConfigType
let arg = (devices:DeviceEntities,DeviceStartIndex,inputStartIndex,outputStartIndex)
match bar with
| barConfig1 -> configType1(arg) :> IConfigType
| barConfig2 -> configType2(arg) :> IConfigType
| barConfig3 -> configType3(arg) :> IConfigType
| barConfig4 -> configType4(arg) :> IConfigType
回答2:
If the output type has a limited number of cases, you can make that a discriminated union as well:
type ConfigType =
| ConfigType1 of configType1
| ConfigType2 of configType2
| ConfigType3 of configType3
| ConfigType4 of configType4``
let foo =
match bar with
| barConfig1 -> ConfigType1 <| configType1(devices:DeviceEntities,DeviceStartIndex,inputStartIndex,outputStartIndex)
| barConfig2 -> ConfigType2 <| configType2(devices:DeviceEntities,DeviceStartIndex,inputStartIndex,outputStartIndex)
| barConfig3 -> ConfigType3 <| configType3(devices:DeviceEntities,DeviceStartIndex,inputStartIndex,outputStartIndex)
| barConfig4 -> ConfigType4 <| configType4(devices:DeviceEntities,DeviceStartIndex,inputStartIndex,outputStartIndex)``
Alternately, if they all implement an interface or inherit some base class, you can upcast to that, as with scrwtp's answer.
来源:https://stackoverflow.com/questions/26937533/f-how-to-have-a-values-type-determined-by-a-match-statement