Question

Pourquoi les laisser fixations non autorisées dans une union de discrimination? Je suppose qu'il doit faire avec liaisons let en cours d'exécution dans un constructeur par défaut?

Sur une note secondaire des suggestions sur la façon dont je pourrais réécrire AI_Choose serait apprécié. Je veux garder la priorité pondérée dans un tuple avec l'IA. Mon idée est d'avoir AI_Weighted_Priority Hériter AI_Priority et passer outre Choisissez. Je ne veux pas traiter avec des listes zipper de différentes longueurs (mauvaise pratique 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)
Était-ce utile?

La solution

il serait logique de permettre « laisser » liant les syndicats à l'intérieur discriminées. Je pense que la raison pour laquelle il est impossible que les syndicats discriminés sont toujours basés sur la conception OCaml alors que les objets viennent du monde .NET. F # tente d'intégrer ces deux autant que possible, mais il pourrait probablement aller plus loin.

Quoi qu'il en soit, il me semble que vous utilisez l'union discriminante que pour mettre en œuvre un comportement interne du type AI_Choose. Dans ce cas, vous pouvez déclarer une union discrimination séparément et l'utiliser pour mettre en œuvre le type d'objet.

Je crois que vous pourriez écrire quelque chose comme ceci:

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 principale différence entre la hiérarchie des classes et les syndicats discriminés est en ce qui concerne l'extensibilité. Les classes facilitent l'ajout de nouveaux types tandis que les syndicats discriminés facilitent l'ajout de nouvelles fonctions qui fonctionnent avec le type (dans votre AiChooseOptions de cas), de sorte que est probablement la première chose à considérer lors de la conception de l'application.

Autres conseils

Pour toute personne intéressée, je fini par tirer AI_Priority et AI_Weighted_Priority d'une classe de base abstraite.

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

Revisiter ce code, je fini par prendre la suggestion de Tomas qui se un beaucoup plus propre.

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)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top