2012-06-03 49 views
1

比方說,我有一個區分聯合:地圖上的所有值在區分聯合

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是有用的,但它並不完全是我需要的;我希望能夠在內存中訪問聯合成員,而不僅僅是檢查其屬性。

我想這樣做的原因是我可以有一個歧視的聯盟來代表遊戲中所有不同類型的牌,以及一個函數,告訴你每張牌在開始時應該有多少個,然後輕鬆生成卡的初始映射到計數。有一個更好的方法嗎?

+1

你會怎麼做,如果你識別聯合案例之一是string'的'T?然後你需要想出一個構造函數,可以想象'string'可以用在'getCost'中。在這一點上事情變得相當複雜 - 也許你可以告訴我們你正在試圖使用它的? –

+1

我不明白你在問什麼,但是我期待着看到一些關於使用F#的Dominion的博客/應用:) – Brian

回答

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) 
相關問題