Domanda

attacchi Perché sono lasciate non consentiti in un'unione discriminato? Suppongo che ha a che fare con attacchi let in corso di esecuzione in un costruttore di default?

In una nota secondaria qualche suggerimento su come potrei riscrivere AI_Choose sarebbe apprezzato. Voglio mantenere la priorità ponderata in una tupla con l'IA. La mia idea è quella di avere AI_Weighted_Priority ereditare AI_Priority e sovrascrivere Scegli. Non voglio a che fare con zippare liste di diverse lunghezze (cattiva pratica 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)
È stato utile?

Soluzione

avrebbe senso per consentire "lasciare" vincolanti sindacati all'interno discriminati. Penso che il motivo per cui non è possibile è che i sindacati discriminati sono ancora basati sul design OCaml mentre gli oggetti provengono dal mondo .NET. F # sta cercando di integrare questi due, per quanto possibile, ma probabilmente potrebbe andare oltre.

In ogni caso, mi sembra che si sta utilizzando l'unione discriminare solo per implementare un comportamento interno di tipo AI_Choose. In tal caso, si potrebbe dichiarare un'unione discriminati separatamente e utilizzarla per implementare il tipo di oggetto.

Credo che si potrebbe scrivere qualcosa di simile:

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 (...)

La differenza fondamentale tra gerarchia delle classi e dei sindacati discriminati è quando si tratta di estensibilità. Classi rendono più facile aggiungere nuovi tipi mentre i sindacati discriminati rendono più facile aggiungere nuove funzioni che lavorano con il tipo (nel tuo caso AiChooseOptions), in modo che è probabilmente la prima cosa da considerare quando si progetta l'applicazione.

Altri suggerimenti

Per chiunque sia interessato ho finito derivante AI_Priority e AI_Weighted_Priority da una classe base astratta.

[<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

Rivisitare questo codice ho finito per prendere il suggerimento di Tomas che si è rivelata molto più pulito.

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)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top