Reputation: 19
I am not able to return the specific case of a type to another type that just wants to hold the generic case, and not actually implement a specific example. (For example and not related to the types below, instead of returning 0.1 with units of centimeters, I am trying to return centimeters).
My type is defined as follows:
type UnitOfMeasure =
| Foo of decimal
| Bar of decimal
| Baz of decimal
I then also have:
type BlahComponent =
{ Name : string
Units : UnitOfMeasure }
I am given a string representation of the type of UnitOfMeasure, and I am trying to decide which UnitOfMeasure (Foo, Bar, or Baz) I have. I am using the following function:
let decideUnitOfMeasure stringRepresentationOfUnitOfMeasureType =
match stringRepresentationOfUnitOfMeasureType with
| "Foo" -> Foo
| "Bar" -> Bar
| "Baz" -> Baz
Finally, I try to assign the return value of decideUnitOfMeasure to BlahComponent
let stringRepresentationOfUnitOfMeasureType = "Foo"
let bomComponent = {Name = "nameString"
Units = decideUnitOfMeasure stringRepresentationOfUnitOfMeasureType}
Trying to assign the return of decideUnitOfMeasure to Units results in the following error: The expression was expected to have type 'UnitOfMeasure' but has type '(decimal -> UnitOfMeasure)'.
It appears that by the definition of UnitOfMeasure, returning the actual case of Foo, Bar, or Baz is not possible because it requires casting UnitOfMeasure to a decimal. Is there any way to return the actual case without casting to a decimal?
Upvotes: 1
Views: 65
Reputation: 10624
This is not about casting. It is just a type error.
Foo
is a constructor for the UnitOfMeasure
type. It has the type decimal -> UnitOfMeasure
. This means it takes a decimal
value and returns a UnitOfMeasure
.
So Foo
on its own is not a UnitOfMeasure, but Foo 1m
is. Your Units
field actually stores the number as well, and you have not provided the number.
This explains why you are seeing this error. The answer from Chad Gilbert offers a possible alternative approach, but the best approach really depends on what you're trying to do.
Upvotes: 2
Reputation: 36375
You may be best served by redefining UnitOfMeasure
to act more like a simple enumeration, where the constructors have no arguments:
type UnitOfMeasure =
| Foo
| Bar
| Baz
Now you can move the decimal value so that it is not a type parameter. You could create a record type or even keep it as a simple tuple:
type BlahComponent =
{ Name : string
Value : UnitOfMeasure * decimal }
Upvotes: 2