الاتحاد التمييز ودع ملزمة؟
-
19-09-2019 - |
سؤال
لماذا تدع الروابط غير مسموح بها في الاتحاد التمييز؟ أفترض أنه يجب القيام به مع ترك الارتباطات التي يتم تنفيذها في منشئ افتراضي؟
في ملاحظة ثانوية، أي اقتراحات حول كيفية إعادة كتابة AI_Choose
سيكون موضع تقدير. أريد أن أبقي الأولوية المرجحة في tuple مع منظمة العفو الدولية. فكرتي هي أن يكون AI_Weighted_Priority
يرث AI_Priority
وتجاوز الاختيار. لا أريد التعامل مع قوائم Zipping بأطوال مختلفة (ممارسة سيئة للغاية)
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)
المحلول
من المنطقي السماح ب "دع" ملزمة داخل النقابات التمييزية. أعتقد أن السبب في أنه غير ممكن هو أن النقابات التمييزية لا تزال قائمة على تصميم OCAML بينما تأتي الكائنات من World .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)، لذلك ربما يكون هذا أول شيء يجب مراعاته عند تصميم التطبيق.
نصائح أخرى
لأي شخص مهتم انتهى بي الأمر 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)