Diskriminierte Union und lassen verbindlich?
-
19-09-2019 - |
Frage
Warum Bindungen werden lassen nicht in einer diskriminierte Vereinigung erlaubt? Ich nehme an, es hat mit let-Bindungen zu tun, in einem Standard-Konstruktor ausgeführt werden?
Auf einer sekundäre Anmerkung Vorschläge, wie ich AI_Choose
umschreiben könnte würden geschätzt. Ich möchte mit der KI die gewichtete Priorität in einem Tupel zu halten. Meine Idee ist AI_Weighted_Priority
erben AI_Priority
zu haben, und überschreiben wählen. Ich will nicht mit zippen Listen unterschiedlicher Länge bewältigen (imo schlechte Praxis.)
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)
Lösung
würde es Sinn machen „lassen“ Bindung innerhalb diskriminiert Gewerkschaften zu ermöglichen. Ich denke, den Grund, warum es nicht möglich ist, ist, dass diskriminierte Gewerkschaften nach wie vor auf dem OCaml-Design basieren, während Objekte aus der .NET-Welt kommen. F # versucht, diese beiden so viel wie möglich zu integrieren, aber es könnte wohl weiter gehen.
Wie auch immer, es scheint mir, dass Sie die diskriminieren Vereinigung verwenden nur einige interne Verhalten des AI_Choose
Typ zu implementieren. In diesem Fall könnten Sie eine diskriminierte Vereinigung separat deklarieren und es verwenden, um den Objekttyp zu implementieren.
Ich glaube, Sie so etwas schreiben könnte:
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 (...)
Der wesentliche Unterschied zwischen Klassenhierarchie und diskriminierte Gewerkschaften, wenn es um Dehnbarkeit kommt. Klassen machen es einfacher, neue Typen hinzufügen, während diskriminieren Gewerkschaften machen es einfacher, neue Funktionen hinzuzufügen, dass die Arbeit mit der Art (in Ihrem Fall AiChooseOptions), so dass wahrscheinlich das erste, was ist zu beachten, wenn die Entwicklung neuer Anwendungen.
Andere Tipps
Für alle Interessierten ich am Ende AI_Priority
und AI_Weighted_Priority
von einer abstrakten Basisklasse abgeleitet wird.
[<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
Neubetrachtung diesen Code I Tomas Vorschlag nimmt schließlich die viel sauberer geworden ist.
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)