单值歧视工会?
Single value discriminated unions?
在F#中是否可以有一个只赋值一次的可区分联合?我在想象这样的事情:
type DogAttributes = { Age: int; Color: string; }
type Dog =
| Rex of DogAttributes ({ Age = 5; Color = "Brown"; }
| Fido of DogAttributes ({ Age = 3; Color = "White"; }
Rex 值将始终具有分配的 DogAttributes 且无法更改。
此代码将完成您想要的:
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")
但是,在这一点上,您似乎最好只使用 OO 风格的多态性。 有区别的并集不是表达求和类型的唯一方式†,只是最好的。但是,抽象 类 也可以起到同样的作用。
†证明:此答案中描述的代码。
正如@rmunn 所指出的,您似乎混淆了类型和值。 Rex
和 Fido
应该是同一实体的实例。
type Dog = { Name: string; Age: int; Color: string }
歧视工会这里也没有,可以考虑枚举有好处
type Breed =
| JackRussell
| Labrador
| Poodle
你当然可以把它们结合起来...
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
...但是在给定的上下文中,你会做更多的匹配而不是理想的。
type GoodDog = { Name: string; Age: int; Color: string; Breed: Breed }
let goodJack = { Name = "Rex" ; Age = 5 ; Color = "brown" ; Breed = Breed.JackRussell } // (*)
(*) 如果没有 BadDog
类型定义,您可以使用 JackRussell
而不是 Breed.JackRussell
(解决歧义)。
您在评论中提到希望以更直接的方式匹配狗的名字。考虑这个 active pattern:
let (|DogName|) = function dog -> dog.Name
match goodJack with
| DogName "Rex"
-> printfn "Hello Rex"
| _ -> printfn "Hello world"
在F#中是否可以有一个只赋值一次的可区分联合?我在想象这样的事情:
type DogAttributes = { Age: int; Color: string; }
type Dog =
| Rex of DogAttributes ({ Age = 5; Color = "Brown"; }
| Fido of DogAttributes ({ Age = 3; Color = "White"; }
Rex 值将始终具有分配的 DogAttributes 且无法更改。
此代码将完成您想要的:
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")
但是,在这一点上,您似乎最好只使用 OO 风格的多态性。 有区别的并集不是表达求和类型的唯一方式†,只是最好的。但是,抽象 类 也可以起到同样的作用。
†证明:此答案中描述的代码。
正如@rmunn 所指出的,您似乎混淆了类型和值。 Rex
和 Fido
应该是同一实体的实例。
type Dog = { Name: string; Age: int; Color: string }
歧视工会这里也没有,可以考虑枚举有好处
type Breed =
| JackRussell
| Labrador
| Poodle
你当然可以把它们结合起来...
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
...但是在给定的上下文中,你会做更多的匹配而不是理想的。
type GoodDog = { Name: string; Age: int; Color: string; Breed: Breed }
let goodJack = { Name = "Rex" ; Age = 5 ; Color = "brown" ; Breed = Breed.JackRussell } // (*)
(*) 如果没有 BadDog
类型定义,您可以使用 JackRussell
而不是 Breed.JackRussell
(解决歧义)。
您在评论中提到希望以更直接的方式匹配狗的名字。考虑这个 active pattern:
let (|DogName|) = function dog -> dog.Name
match goodJack with
| DogName "Rex"
-> printfn "Hello Rex"
| _ -> printfn "Hello world"