Why are let bindings not permitted in a discriminated union? I assume it has to do with let bindings being executed in a default constructor?
On a secondary note any suggestions on how I could rewrite AI_Choose
would be appreciated. I want to keep the weighted priority in a tuple with the AI. My idea is to have AI_Weighted_Priority
inherit AI_Priority
and override Choose. I don't want to deal with zipping lists of different lengths (bad practice 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)
it would make sense to allow "let" binding inside discriminated unions. I think the reason why it isn't possible is that discriminated unions are still based on the OCaml design while objects come from the .NET world. F# is trying to integrate these two as much as possible, but it could probably go further.
Anyway, it seems to me that you're using the discriminate union only to implement some internal behavior of the
AI_Choose
type. In that case, you could declare a discriminated union separately and use it to implement the object type.I believe you could write something like this:
The key difference between class hierarchy and discriminated unions is when it comes to extensibility. Classes make it easier to add new types while discriminated unions make it easier to add new functions that work with the type (in your case AiChooseOptions), so that's probably the first thing to consider when designing the application.