假设你有这样一个并集:
type Thing =
| Eagle
| Elephant of int
你的代码有一个大象列表,如
let l = [Elephant (1000); Elephant (1200)]
您想迭代l
,并打印出与每个Elephant
相关的数据。有没有一种不使用模式匹配的方法?
在您的示例中,您说您有一个大象列表-这在本例中是正确的-但l
的类型实际上是Thing
值的列表,因此它可以包含大象和鹰。这就是为什么你需要使用模式匹配-来处理所有可能的情况。
type ElephantInfo = { Size : int }
type Thing =
| Elephant of ElephantInfo
| Eagle
现在你可以创建一个list<ElephantInfo>
类型的列表,它可以只包含大象,所以你不需要模式匹配:
let l1 = [ {Size=1}; {Size=2} ]
for el in l1 do printfn "%d" el.Size
另一方面,如果你想混合大象和鹰,你将创建list<Thing>
,然后使用模式匹配:
let l2 = [ Elephant {Size=1}; Eagle ]
你可以这样做:
l
|> List.collect (function Elephant x -> [x] | _ -> [])
|> List.iter (printfn "%i")
打印
1000
1200
它仍然使用模式匹配,但它是相当少的。
您当然可以选择完全象牙塔 (®斯科特Wlaschin)
如about:
type Thing =
| Eagle
| Elephant of int
type MaybeElephantBuilder() =
member this.Bind(x, f) =
match x with
| Eagle -> 0
| Elephant a -> f a
member this.Return(x) = x
let maybeElephant = new MaybeElephantBuilder()
let l =
[ Elephant(1000)
Elephant(1200)
]
let printIt v =
let i =
maybeElephant {
let! elephantValue = v
return elephantValue
}
printfn "%d" i
l |> Seq.iter printIt
它甚至可以处理老鹰扔进去的东西!
嗯…
删除非鹰,代码将飞行…
let l =
[ Eagle
Leadon
Elephant(1000)
Eagle
Meisner
Elephant(1200)
Eagle
Felder
]
l |> Seq.iter printIt
但没有。这不太好。它不短。它更多的是为了好玩(如果有的话!)。这可能也是对f#计算表达式最糟糕的误用!
你的将需要模式匹配的地方。
Thx斯科特!和Petricek。
计算表达式动物园的真实!: -)
您可以使用Microsoft.FSharp.Reflection
Namespace的反射,但它更麻烦,更慢。
模式匹配可能是从区别并集中获取数据的最简单方法。
(你也有一个Things
的列表,它的所有成员恰好是Elephant
的联合情况)。
有一种方法可以将模式匹配放置到函数的头中(或let
绑定)。尽管如此,它仍然是一个模式匹配。
// This function takes a tuple:
// the first argument is a Thing,
// the second is "default" weight to be processed if the first one is NOT an Elephant
let processElephant (Elephant weight, _ | _, weight) =
weight
let [<Literal>] NON_ELEPHANT_WEIGHT = -1
// usage:
let totalWeight =
[Elephant (1000); Elephant (1200)]
|> List.sumBy (fun el -> processElephant(el, NON_ELEPHANT_WEIGHT))
这个问题及其答案提供了更多的细节