2009-08-26 95 views
6

爲什麼在受歧視的工會中不允許綁定?我認爲它必須與讓綁定在默認構造函數中執行?歧視聯盟和讓綁定?

在次要記錄中,有關如何重寫AI_Choose的建議將不勝感激。我想用AI保持加權優先級。我的想法是讓AI_Weighted_Priority繼承AI_Priority並覆蓋選擇。我不想處理荏苒不同長度的列表(不好的做法IMO)

open AI 

type Condition = 
    | Closest of float 
    | Min 
    | Max 
    | Average 
    member this.Select (aiListWeight : list<AI * float>) = 
     match this with 
     | Closest(x) -> 
      aiListWeight 
      |> List.minBy (fun (ai, priority) -> abs(x - priority)) 
     | Min -> aiListWeight |> List.minBy snd 
     | Max -> aiListWeight |> List.maxBy snd 
     | Average -> 
      let average = aiListWeight |> List.averageBy snd 
      aiListWeight 
      |> List.minBy (fun (ai, priority) -> abs(average - priority)) 

type AI_Choose = 
    | AI_Priority of list<AI> * Condition 
    | AI_Weighted_Priority of list<AI * float> * Condition 

    // I'm sad that I can't do this  
    let mutable chosen = Option<AI>.None 

    member this.Choose() = 
     match this with 
     | AI_Priority(aiList, condition) -> 
      aiList 
      |> List.map (fun ai -> ai, ai.Priority()) 
      |> condition.Select 
      |> fst 
     | AI_Weighted_Priority(aiList, condition) -> 
      aiList 
      |> List.map (fun (ai, weight) -> ai, weight * ai.Priority()) 
      |> condition.Select 
      |> fst 

    member this.Chosen 
     with get() = 
      if Option.isNone chosen then 
       chosen <- Some(this.Choose()) 
      chosen.Value 
     and set(x) = 
      if Option.isSome chosen then 
       chosen.Value.Stop() 
      chosen <- Some(x) 
      x.Start() 

    interface AI with 
     member this.Start() = 
      this.Chosen.Start() 
     member this.Stop() = 
      this.Chosen.Stop() 
     member this.Reset() = 
      this.Chosen <- this.Choose() 
     member this.Priority() = 
      this.Chosen.Priority() 
     member this.Update(gameTime) = 
      this.Chosen.Update(gameTime) 

回答

2

允許在被區分的聯合中「let」綁定是有意義的。我認爲不可能的原因是受歧視的工會仍然基於OCaml設計,而對象來自.NET世界。 F#正試圖儘可能地整合這兩者,但它可能會更進一步。

無論如何,在我看來,你使用歧視聯盟只是爲了實現AI_Choose類型的一些內部行爲。在這種情況下,您可以分別聲明一個區分的聯合,並使用它來實現對象類型。

我相信你可以寫這樣的事情:

type AiChooseOptions = 
    | AI_Priority of list<AI> * Condition 
    | AI_Weighted_Priority of list<AI * float> * Condition 

type AiChoose(aiOptions) = 
    let mutable chosen = Option<AI>.None 
    member this.Choose() = 
     match aiOptions with 
     | AI_Priority(aiList, condition) -> (...) 
     | AI_Weighted_Priority(aiList, condition) -> (...) 
    member this.Chosen (...) 
    interface AI with (...) 

類層次結構和可識別聯合之間的主要區別是,當涉及到可擴展性。類使得添加新類型變得更加容易,而區分的聯合可以更容易地添加與類型配合使用的新函數(在您的情況中,AiChooseOptions),所以這可能是設計應用程序時首先要考慮的事情。

3

任何有興趣我結束了從抽象基類派生AI_PriorityAI_Weighted_Priority

[<AbstractClass>] 
type AI_Choose() = 
    let mutable chosen = Option<AI>.None 

    abstract member Choose : unit -> AI 

    member this.Chosen 
     with get() = 
      if Option.isNone chosen then 
       chosen <- Some(this.Choose()) 
      chosen.Value 
     and set(x) = 
      if Option.isSome chosen then 
       chosen.Value.Stop() 
      chosen <- Some(x) 
      x.Start() 

    interface AI with 
     member this.Start() = 
      this.Chosen.Start() 
     member this.Stop() = 
      this.Chosen.Stop() 
     member this.Reset() = 
      this.Chosen <- this.Choose() 
     member this.Priority() = 
      this.Chosen.Priority() 
     member this.Update(gameTime) = 
      this.Chosen.Update(gameTime) 

type AI_Priority(aiList : list<AI>, condition : Condition) = 
    inherit AI_Choose() 
    override this.Choose() = 
     aiList 
     |> List.map (fun ai -> ai, ai.Priority()) 
     |> condition.Select 
     |> fst 

type AI_Weighted_Priority(aiList : list<AI * float>, condition : Condition) = 
    inherit AI_Choose() 
    override this.Choose() = 
     aiList 
     |> List.map (fun (ai, weight) -> ai, weight * ai.Priority()) 
     |> condition.Select 
     |> fst 
3

重溫這段代碼我最終採取了Tomas的建議,結果證明它更加清潔。

type AiChooseOptions = 
    | Priority of List<AI * Priority> 
    | WeightedPriority of List<AI * Priority * float> 
    member this.Choose(condition : Condition) = 
     match this with 
     | Priority(list) -> 
      list 
      |> List.map (fun (ai, priority) -> ai, priority.Priority()) 
      |> condition.Select 
     | WeightedPriority(list) -> 
      list 
      |> List.map (fun (ai, p, weight) -> ai, p.Priority() * weight) 
      |> condition.Select 

type AiChoose(condition, list : AiChooseOptions) = 
    let mutable chosen = Unchecked.defaultof<AI>, 0.0 

    interface AI with 
     member this.Update(gameTime) = 
      (fst chosen).Update(gameTime) 

    interface Priority with 
     member this.Priority() = 
      chosen <- list.Choose(condition) 
      (snd chosen)