Function associated with a union type and hiding the matching logic
Takes N+1 parameters for a union type with N cases
Example
type [<Measure>] C
type [<Measure>] F
type Temperature =
| Celsius of float<C>
| Fahrenheint of float<F>
module Temperature =
let fold mapCelsius mapFahrenheint temperature : 'T =
match temperature with
| Celsius x -> mapCelsius x // mapCelsius : float<C> -> 'T
| Fahrenheint x -> mapFahrenheint x // mapFahrenheint: float<F> -> 'T
let private [<Literal>] FactorC2F = 1.8<F/C>
let private [<Literal>] DeltaC2F = 32.0<F>
let celsiusToFahrenheint x = (x * FactorC2F) + DeltaC2F // float<C> -> float<F>
let fahrenheintToCelsius x = (x - DeltaC2F) / FactorC2F // float<F> -> float<C>
let toggleUnit temperature =
temperature |> fold
(celsiusToFahrenheint >> Fahrenheint)
(fahrenheintToCelsius >> Celsius)
let t1 = Celsius 100.0<C>
let t2 = t1 |> Temperature.toggleUnit // Fahrenheint 212.0
Advantages
fold hides the implementation details of the type
For example, we could add a Kelvincase and only impact fold, not the functions that call it, such as toggleUnit in the previous example
type [<Measure>] C
type [<Measure>] F
type [<Measure>] K // 🌟
type Temperature =
| Celsius of float<C>
| Fahrenheint of float<F>
| Kelvin of float<K> // 🌟
module Temperature =
let fold mapCelsius mapFahrenheint temperature : 'T =
match temperature with
| Celsius x -> mapCelsius x // mapCelsius: float<C> -> 'T
| Fahrenheint x -> mapFahrenheint x // mapFahrenheint: float<F> -> 'T
| Kelvin x -> mapCelsius (x * 1.0<C/K> + 273.15<C>) // 🌟
Kelvin 273.15<K>
|> Temperature.toggleUnit
// Celsius 0.0<C>