識別型ユニオンと結合させ?
-
19-09-2019 - |
質問
なぜ聞かせているバインディングを判別組合では許可されていませんか?私はそれがデフォルトコンストラクタで実行されているのletバインディングに関係していると仮定?
二ノートで、私はAI_Choose
を書き換えることができる方法上の任意の提案をいただければ幸いです。私は、AIとのタプルで加重優先順位を維持したいです。私の考えはAI_Weighted_Priority
を継承し、選択して上書きAI_Priority
持つことです。私は、異なる長さのリストをビュンに対処する必要はありません(悪い習慣芋。)
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)
解決
これは、判別共用体の内側に結合「しましょう」できるように理にかなって。私はそれが不可能な理由は、オブジェクトが、.NETの世界から来ながら判別組合がまだOCamlの設計に基づいていることだと思います。 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に)タイプで動作する新しい機能を追加するために作りながら、それが簡単に新しいタイプを追加するために作るので、それはおそらく、アプリケーションを設計する際に考慮すべき最初のことだ。
他のヒント
興味がある人のために私は、抽象基本クラスからAI_Priority
とAI_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
私はたくさんのクリーナーを判明トーマスの提案を取ってしまった。
このコードを再訪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)