Is it possible in F# to have a discriminated union whose value is assigned only once? I'm imagining something like:
type DogAttributes = { Age: int; Color: string; }
type Dog =
| Rex of DogAttributes ({ Age = 5; Color = "Brown"; }
| Fido of DogAttributes ({ Age = 3; Color = "White"; }
The Rex value would always have the assigned DogAttributes and couldn't be changed.
As pointed out by #rmunn it seems like you're confusing types with values. Rex and Fido should be instances of the same entity.
type Dog = { Name: string; Age: int; Color: string }
Discriminated Unions aren't in place here either, they can be considered Enums with benefits.
type Breed =
| JackRussell
| Labrador
| Poodle
You could of course combine them...
type BadDog =
| JackRussell of Dog
| Labrador of Dog
| Poodle of Dog
let badJack = JackRussell({ Name = "Rex" ; Age = 5 ; Color = "brown" })
let badName =
match badJack with
| JackRussell(dog)
| Labrador(dog)
| Poodle(dog)
-> dog.Name
...but in the given context you'd be doing more matching then desirable.
type GoodDog = { Name: string; Age: int; Color: string; Breed: Breed }
let goodJack = { Name = "Rex" ; Age = 5 ; Color = "brown" ; Breed = Breed.JackRussell } // (*)
(*) Without the BadDog type definition you could've used JackRussell instead of Breed.JackRussell (resolving ambiguity).
In the comments you mentioned wanting to match against the dog's name in a more direct way. Consider this active pattern:
let (|DogName|) = function dog -> dog.Name
match goodJack with
| DogName "Rex"
-> printfn "Hello Rex"
| _ -> printfn "Hello world"
This code would accomplish what you want:
type DogAttribute = { Age : int; Color : string }
type Dog =
| Rex of DogAttribute
| Fido of DogAttribute
[<AbstractClass>]
type DogBase(dog, age, color) =
member x.Age = age
member x.Color = color
member x.Dog = dog { Age = x.Age; Color = x.Color}
type Rex() =
inherit DogBase(Dog.Rex, 5, "Brown")
type Fido() =
inherit DogBase(Dog.Fido, 3, "White")
But, at that point, it seems like you'd be better off just using OO-style polymorphism. Discriminated unions aren't the only way to express a sum type†, just the nicest. But, abstract classes can serve just as well.
†Proof: The code described in this answer.
Related
How do I type let's say a function that takes a record that has a field a and any other field?
Is some equivalent of this Standard ML function possible in F#?
fun f {a: string, ...} = "Hello" ^ a;
Tried the following but these don't seem to be syntactically valid:
let f (r: {|a: string; _|}) = impl;
let g (r: {|a: string; ...|}) = impl;
You can achieve this kind of constraint with Statically Resolved Type Parameters like so:
let inline f< ^T when ^T: (member a: string)> (r: ^T) = ()
f {| a = "yeet" |} // compiles
f {| a = "yeet"; b = "yote" |} // compiles
f {| b = "yote" |} // error
Note that this isn't just for anonymous records. It will hold true for any type that has a member with the specified signature.
I also like to hide these things behind a module and extract the nasty SRTP stuff into an active pattern like so:
module M =
let inline private (|HasName|) x = (^a : (member Name: string) x)
let inline printName (HasName name) = printfn $"{name}"
type Person1 = { Name: string; Age: int }
type Person2 = { Name: string; Age: int; IsFunny: bool }
type Name(name) =
member _.Name = name
let p1 = { Name = "Phillip"; Age = 30 }
let p2 = { Name = "Phillip"; Age = 30; IsFunny = false }
let nm = Name "Phillip"
M.printName p1
M.printName p2
M.printName nm
This has the benefit of hiding the details of how you get the constraint "lined up correctly" and lets you easily re-use the signature in other things you want to publicly expose.
I have read quite a few ressources on Unit of Measures (including the good Microsoft Doc and f# for fun and profit) but I still cannot make my code work.
[<Measure>] type USD
[<Measure>] type JPY
[<Measure>] type EUR
type FxUnit<[<Measure>] 'u,[<Measure>] 'v> = {UnitRate : float<'u/'v>}
let getFx1 u =
match u with
| "USD" -> {UnitRate = 1.0<USD/USD>}
| "EUR" -> {UnitRate = 1.0<USD/EUR>}
This way I get an error under:
1.0<USD/EUR>
I have tried thse:
let getFx1 u : (float<'u>) =
let getFx1 u : (float<'u/'v>) =
without much success. It seems that with a match, I can't return some type FxUnit with different UoM.
Any idea how I could fix this?
thanks.
The problem is that you're trying to define a function that takes a string and returns a value of type either FxUnit<USD,USD> or FxUnit<USD,EUR>. A function can't have two different return types, decided at runtime.
You could make FxUnit take two values of a discriminated union instead of measures:
type Currency =
| USD
| JPY
| EUR
type FxUnit = { UnitRate : float; From : Currency; To : Currency }
let getFx1 u =
match u with
| "USD" -> {UnitRate = 1.0; From = USD; To = USD}
| "EUR" -> {UnitRate = 1.0; From = USD; To = EUR}
| _ -> failwithf "Unrecognised units %s" u
Given the following:
type IFruit = interface end
type Avocado = { color : string; age : int } interface IFruit
let (|AvocadoTexture|) (a : Avocado) = if a.age < 7 then "firm" else "mushy"
... Why does this work:
let texture (f : IFruit) =
match f with
| :? Avocado as a -> if a.age < 7 then "firm" else "mushy"
| _ -> String.Empty
... but not this?
let texture (fruit : IFruit) =
match fruit with
| AvocadoTexture t -> t // "The type IFruit does not match the type Avocado"
| _ -> String.Empty
fruit may be any IFruit, but the AvocadoTexture Active Pattern only accepts the specific implementation Avocado, as per the type annotation of a.
If you want the Active Pattern to accept any IFruit, but only return a useful value for an Avocado, you can make it partial:
let (|AvocadoTexture|_|) (f : IFruit) =
match f with
| :? Avocado as a ->
if a.age < 7 then "firm" else "mushy"
|> Some
| _ -> None
Now your texture function works as you wanted:
let texture (fruit : IFruit) =
match fruit with
| AvocadoTexture t -> t
| _ -> String.Empty
Just bear in mind that there are Partial Active Patterns and Active Patterns. Active Patterns have up to 7 tags that something can be concretely matched against. Both forms are useful.
Active Patterns are better if you want the compiler to tell you all the places where you've missed handling a case after you've decided that you need an extra one. The compiler can be configured to flag this as an error rather than a warning if you want to be extra strict about it.
open System
type IFruit = interface end
type Avocado =
{ color : string; age : int }
interface IFruit
static member tryFromIFruit(x:IFruit) =
match x with
| :? Avocado -> Some(x:?>Avocado)
| _ -> None
let (|Firm|Mushy|) (a : Avocado) = if a.age < 7 then Firm else Mushy
let texture (fruit : IFruit) =
match fruit |> Avocado.tryFromIFruit with // we're not sure if it's an Avocado.
| Some(Firm) -> "firm" // use Some(SomethingElse()) when you want to collapse an extra layer of "match" statements.
| Some(Mushy) -> "mushy"
| None -> ""
texture ( { color = "green"; age = 4 } :> IFruit)
documentation: https://learn.microsoft.com/en-us/dotnet/articles/fsharp/language-reference/active-patterns
If I've got a class hierarchy like
type Employee(name) =
member val name: string = name
type HourlyEmployee(name, rate) =
inherit Employee(name)
member val rate: int = rate
type SalariedEmployee(name, salary) =
inherit Employee(salary)
member val salary: int = salary
And I want a function that updates the name field in a pure way, how is this possible? A couple failed options:
let changeName(employee: Employee) =
// no idea what class this was, so this can only return the base class
let changeName<'a when 'a :> Employee>(employee: 'a) =
// 'a has no constructor
The closest thing I've come up with is making a virtual Employee.changeName and implementing that on each class. That just seems like a lot of extra work plus it's error-prone since the return type is Employee and has to be upcasted back to the original class.
Seems like there should be a simpler, safer way to do such a task. Is this something where typeclasses are necessary?
Update
Yes I could just make the name field mutable, which is how it is implemented in my code now, but that's what I'm wanting to get away from.
Update 2
A solution I've come up with, that meets type safety and conciseness requirements, would be to define
type Employee<'a> = {name: string; otherStuff: 'a}
and then just use with syntax to change the name. But otherStuff: 'a is obviously ugly and hacky looking code, so I'm still open to better solutions.
If you're looking for something both pure and idiomatic F#, then you shouldn't be using an inheritance hierarchy in the first place. That's an object-oriented concept.
In F#, you could model Employee like this, using algebraic data types:
type HourlyData = { Name : string; Rate : int }
type SalaryData = { Name : string; Salary : int }
type Employee =
| Hourly of HourlyData
| Salaried of SalaryData
This would enable you to create Employee values like this:
> let he = Hourly { Name = "Bob"; Rate = 100 };;
val he : Employee = Hourly {Name = "Bob";
Rate = 100;}
> let se = Salaried { Name = "Jane"; Salary = 10000 };;
val se : Employee = Salaried {Name = "Jane";
Salary = 10000;}
You can also define a function to change the name in a pure manner:
let changeName newName = function
| Hourly h -> Hourly { h with Name = newName }
| Salaried s -> Salaried { s with Name = newName }
This enables you to change the name of an existing Employee value like this:
> let se' = se |> changeName "Mary";;
val se' : Employee = Salaried {Name = "Mary";
Salary = 10000;}
Is it possible to add constant field values to F# discriminated unions?
Can I do something like this?
type Suit
| Clubs("C")
| Diamonds("D")
| Hearts("H")
| Spades("S")
with
override this.ToString() =
// print out the letter associated with the specific item
end
If I were writing a Java enum, I would add a private value to the constructor like so:
public enum Suit {
CLUBS("C"),
DIAMONDS("D"),
HEARTS("H"),
SPADES("S");
private final String symbol;
Suit(final String symbol) {
this.symbol = symbol;
}
#Override
public String toString() {
return symbol;
}
}
Just for completeness this is what is meant:
type Suit =
| Clubs
| Diamonds
| Hearts
| Spades
with
override this.ToString() =
match this with
| Clubs -> "C"
| Diamonds -> "D"
| Hearts -> "H"
| Spades -> "S"
The closest thing to your requirement is F# enums:
type Suit =
| Diamonds = 'D'
| Clubs = 'C'
| Hearts = 'H'
| Spades = 'S'
let a = Suit.Spades.ToString("g");;
// val a : string = "Spades"
let b = Suit.Spades.ToString("d");;
// val b : string = "S"
The problem with F# enums is non-exhaustive pattern matching. You have to use wildcard (_) as the last pattern when manipulating enums. Therefore, people tend to prefer discriminated unions and write explicit ToString function.
Another solution is to make a mapping between constructors and corresponding string values. This is helpful in case we need to add more constructors:
type SuitFactory() =
static member Names = dict [ Clubs, "C";
Diamonds, "D";
Hearts, "H";
Spades, "S" ]
and Suit =
| Clubs
| Diamonds
| Hearts
| Spades
with override x.ToString() = SuitFactory.Names.[x]
Pretty sure you can't, but is trivial to write a function that pattern matches and then compose the two things