mon*_*res 9 f# pattern-matching discriminated-union
是否可以将有区别的联合标记的类型传递给另一个函数,以便它可以用于模式匹配?
我的意思是非工作的例子:
type Animal = Pig of string | Cow of string | Fish of string
let animals = [Pig "Mike"; Pig "Sarah"; Fish "Eve"; Cow "Laura"; Pig "John"]
let rec filterAnimals animalType animals =
if animals = [] then
[]
else
let rest = filterAnimals animalType (List.tail animals)
match List.head animals with
|animalType animal -> animal::rest // <- this doesn't work
|_ -> rest
printfn "%A" (filterAnimals Pig animals)
Run Code Online (Sandbox Code Playgroud)
Sør*_*ois 13
如果案例之间没有语义重叠,则受歧视的联合最有效.
在您的示例中,每个案例包含具有相同含义的相同组件,a string表示"动物的名称".但那是语义上的重叠!然后,鉴别工会会强迫你做你不想区分到:你不希望被迫的,"一头牛的名字","一头猪的名字"来区分; 你只想想想"动物的名字".
让我们做一个更适合的类型:
type Animal = Pig | Cow | Fish
type Pet = Animal * string
let animals = [(Pig, "Mike"); (Fish, "Eve"); (Pig, "Romeo")
Run Code Online (Sandbox Code Playgroud)
使用该类型,过滤掉非Pigs是一个单行:
animals |> List.filter (fst >> (=) Pig)
Run Code Online (Sandbox Code Playgroud)
如果不是每个动物都有名字,请使用选项类型:
type Pet = Animal * string option
Run Code Online (Sandbox Code Playgroud)
如果你知道每个人都有一个名字,你会使用一个受歧视的联盟Pig,但是没有Fish:这些情况没有重叠.
您可以更改filterAnimals函数以将" 部分活动模式"作为输入:
let rec filterAnimals (|IsAnimalType|_|) animals =
if animals = [] then
[]
else
let rest = filterAnimals (|IsAnimalType|_|) (List.tail animals)
match List.head animals with
| IsAnimalType animal -> animal::rest
| _ -> rest
Run Code Online (Sandbox Code Playgroud)
然后,您可以为猪定义活动部分模式:
let (|IsPig|_|) candidate =
match candidate with
| Pig(_) -> Some candidate
| _ -> None
Run Code Online (Sandbox Code Playgroud)
你可以像这样调用函数(FSI示例):
> filterAnimals (|IsPig|_|) animals;;
val it : Animal list = [Pig "Mike"; Pig "Sarah"; Pig "John"]
Run Code Online (Sandbox Code Playgroud)
实际上,您可以像这样减少部分活动模式:
let (|IsPig|_|) = function | Pig(x) -> Some(Pig(x)) | _ -> None
Run Code Online (Sandbox Code Playgroud)
事实证明,你甚至可以内联它们:
> filterAnimals (function | Pig(x) -> Some(Pig(x)) | _ -> None) animals;;
val it : Animal list = [Pig "Mike"; Pig "Sarah"; Pig "John"]
> filterAnimals (function | Fish(x) -> Some(Fish(x)) | _ -> None) animals;;
val it : Animal list = [Fish "Eve"]
> filterAnimals (function | Cow(x) -> Some(Cow(x)) | _ -> None) animals;;
val it : Animal list = [Cow "Laura"]
Run Code Online (Sandbox Code Playgroud)