2009-11-22 6 views
3

J'ai un certain nombre d'événements qui se produisent dans une partie. Je veux contrôler l'heure et l'ordre dans lesquels ces événements se produisent.F #: Stockage et mappage d'une liste de fonctions

Par exemple:

Event 1: Afficher un texte sur l'écran pour N trames & jouent un effet sonore

Event 2: Effacer le texte sur l'écran

Ma solution (peut-être il y a un meilleur), est d'avoir une liste de fonctions qui contiennent les événements. Les événements exécutent leur comportement puis retournent les prochains événements à se produire dans le jeu. J'ai pensé à utiliser List.map ou List.collect parce que je suis essentiellement mappant une liste d'événements à une nouvelle liste d'événements tout en exécutant du code de comportement.

Dans l'exemple ci-dessus, Event1 peut être composé de deux fonctions: une qui affiche du texte et une qui lit un son (d'où la nécessité d'une liste). La fonction qui affiche le texte renverrait une copie de lui-même pour N-1 images alors il retournerait Event2 qui efface le texte. La fonction de lecture sonore renvoie l'équivalent d'une opération non-op.

Si c'est une bonne solution, je pourrais probablement le faire en C++ ou en C#. Mon but est de faire une solution équivalente ou meilleure en F #.

+0

Quel est le problème que vous essayez de résoudre avec votre liste de fonctions? –

+0

J'ai modifié ma question initiale telle qu'elle était définie dans l'espace de solution; pas d'espace problème. J'espère que cela clarifie les choses. – rysama

Répondre

5

Voulez-vous dire quelque chose comme ça?

let myActions = 
    [fun() -> printfn "You've woken up a dragon." 
    fun() -> printfn "You hit the dragon for 0 points of damage." 
    fun() -> printfn "The dragon belches." 
    fun() -> printfn "You have died."] 

let actionBuilder actionList = 
    let actions = ref actionList 
    fun() -> 
     match !actions with 
     | [] ->() 
     | h::t -> h(); actions := t 

Utilisation (F # interactive):

> let doSomething = actionBuilder myActions;; 

val doSomething : (unit -> unit) 

> doSomething();; 
You've woken up a dragon. 
val it : unit =() 
> doSomething();; 
You hit the dragon for 0 points of damage. 
val it : unit =() 
> doSomething();; 
The dragon belches. 
val it : unit =() 
> doSomething();; 
You have died. 
val it : unit =() 
> doSomething();; 
val it : unit =() 
> 

** Edit: ** si vous voulez être en mesure d'ajouter des actions, peut-être qu'il est préférable de faire un distributeur d'action qui utilise une file d'attente interne, depuis O est AJOUT dE (N) avec une liste et O (1) avec une file d'attente:

type actionGenerator(myActions: (unit->unit) list) = 
    let Q = new System.Collections.Generic.Queue<_>(Seq.ofList myActions) 

    member g.NextAction = 
     fun() -> 
      if Q.Count = 0 then() 
      else Q.Dequeue()() 

    member g.AddAction(action) = Q.Enqueue(action) 
+0

Bonne réponse, et +1 pour mettre l'effort dans une question ambiguë! – Benjol

2

Vous ne savez pas exactement ce que vous essayez de réaliser ici ... il peut être utile de réfléchir aux types exacts que vous recherchez. Il semble que vous souhaitiez peut-être mapper un (unit->(unit->unit)) list sur un (unit->unit) list en appliquant chaque fonction dans le premier. Si tel est le cas, vous pouvez le faire comme ceci:

let l = [(fun() -> (fun() -> printfn "first nested fn")); (fun() -> (fun() -> printfn "second nested fn"))] 
let l' = List.map (fun f -> f()) l 
+0

Mon but est d'enchaîner les appels de fonction. Par exemple, la fonction "foo" retournera la prochaine fonction "bar" à appeler. – rysama

2

Si vous cherchez une syntaxe pour déclarer votre type de liste, voici une façon de le faire:

List<`a->`b> 

Cela suppose que la fonction prend un seul paramètre.

Mais le fait même que vous essayiez de comprendre la syntaxe du type est un indice que vous continuez à regarder cela comme si vous étiez en train de coder en langage procédural.

La façon « fonctionnelle » de le faire est de se concentrer sur la logique de génération de la liste et de laisser le compilateur de déduire le type en fonction de votre code

0

Il semble que vous essayez de faire quelque chose dans un très manière compliquée. C'est parfois nécessaire, mais ce n'est généralement pas le cas.

Puisque vous posez cette question, je suppose que vous avez plus d'expérience dans les langues impératives. Il semble que la solution real à votre problème est quelque chose de complètement différent d'une liste de fonctions.

+0

Ceci n'est pas une réponse c'est un commentaire –

1

J'ai lu votre question deux fois, et je ne suis toujours pas sûr de comprendre exactement ce que vous voulez. Mais d'après ce que je comprends, vos «événements» ne sont pas nécessairement invoqués dans l'ordre où ils apparaissent dans la «liste». Si tel est le cas, vous ne voulez pas vraiment une liste F #, vous voulez une sorte de recherche. Maintenant, l'autre question est de savoir si c'est vraiment une bonne idée pour un événement de déterminer ce qui devrait le suivre? Cela revient à coder durement votre fonctionnalité une fois pour toutes, n'est-ce pas?

EDIT

Je vois dans un commentaire que vous dites que vous voulez « fonction de la chaîne appelle ensemble ».

Que diriez-vous de les écrire l'un après l'autre? Après tout, nous ne sommes pas à Haskell, F # va les virer dans l'ordre où vous les écrivez.

Si vous voulez être un peu plus fonctionnel, vous pouvez utiliser des suites - chaque fonction prend un paramètre supplémentaire qui est la prochaine fonction à exécuter. Presque monadique (je crois), sauf que dans votre cas, ils semblent être des actions, donc il n'y a pas de valeurs à passer d'une fonction à l'autre.

Je ne sais pas si cela vous aide: Je pense que vous devrez essayer de reformuler votre question, à en juger par la diversité des réponses ici.