映射区分联合中的所有值

时间:2012-06-03 02:52:51

标签: reflection f# discriminated-union

假设我有一个受歧视的联盟:

type card = Smithy | Cellar | Chapel

一个将受歧视的联合映射到某个值的函数:

let initialCardCount = function
  Smithy -> 4
  Cellar -> 6
  Chapel -> 2

我想生成一个包含联盟中每个成员的成本的地图,例如:

[(Smithy, 4); (Cellar, 6); (Chapel, 2)]

这可能吗?我希望能够做到这样的事情:

List.zip (allValues f) (List.map getCost (allValues f)) |> Map.ofList

This question很有帮助,但这不是我需要的;我希望能够访问内存中的union成员,而不仅仅是检查它们的属性。

我之所以这样做是因为我可以拥有一个代表游戏中所有不同类型牌的区别联盟,以及一个功能,告诉你每张牌应该在开始时有多少,然后很容易生成卡的初始映射到计数。有更好的方法吗?

1 个答案:

答案 0 :(得分:5)

你可以使用F#Reflection获得所有可能的歧视联合案例的列表,但重要的是要理解反射的缺点 - 除非谨慎使用,否则很容易导致设计不佳(可能更简单,更优雅)它的效率也较低(尽管你可能只需要获取所有案例的列表一次)。

以下getAllValues函数获取所有情况 - 它假定所有情况都不存储任何值(即Smithy of string将无效!)如果您想将一些参数传递给案例,则需要在MakeUnion的第二个参数中传递盒装值:

open Microsoft.FSharp.Reflection

let getAllValues<'T>() : 'T list =
  let cases = FSharpType.GetUnionCases(typeof<'T>)
  [ for c in cases -> unbox (FSharpValue.MakeUnion(c, [| |])) ]

以下是使用场景中的函数的示例:

type card = Smithy | Cellar | Chapel 

let initialCardCount = function 
  | Smithy -> 4 
  | Cellar -> 6 
  | Chapel -> 2 

let values = getAllValues<card>()
List.zip values (List.map initialCardCount values)