2016-01-15 4 views
2

Akka et son port Akka.NET prennent en charge les comportements commutables (http://getakka.net/docs/working-with-actors/Switchable%20Behaviors), et pas seulement dans une forme simple de laisser un acteur à devenir un acteur avec un comportement différent mais aussi sous une forme de pile comportementale: un acteur peut revenir à son comportement précédent. Ceci est réalisé avec les méthodes BecomeStacked et BecomeUnstacked. En F # comportement est pris en charge d'une manière différente: il n'est pas nécessaire Devenir une méthode, à la place une fonction d'acteur peut définir plusieurs gestionnaires de traitement de boîte aux lettres et appeler un autre gestionnaire basculant efficacement un acteur à un comportement différent. Cela fonctionne bien pour les comportements non empilés, mais que se passe-t-il si une fonction d'acteur a besoin d'empiler ses comportements? Comment cela peut-il être implémenté en F #?Akka.NET F # API et les acteurs avec un comportement empilé

MISE À JOUR. Illustrer avec un cas d'utilisation. Considérez la téléphonie où un acteur peut avoir des comportements DirectCall, ConferenceCall et OnHold. Le comportement OnHold est accessible à partir de DirectCall et de ConferenceCall, et lorsqu'un acteur peut recevoir des messages pour démarrer des appels imbriqués. Lorsqu'un appel imbriqué est terminé, un acteur revient à un appel précédent qui peut être DirectCall ou ConferenceCall. Je ne vois pas comment cela peut être implémenté sans envoyer explicitement la pile complète à un acteur. Après tout, ce n'est pas si mal, je me demandais juste s'il y avait une autre façon offerte par Akka.NET. La boîte aux lettres Context.BecomeXXX est toujours disponible dans l'API F #, mais elle n'a pas d'utilité dans l'expression de calcul "acteur".

MISE À JOUR 2 Je suis d'accord avec Tomas Jansson qui raisonnait dans les commentaires qu'il avait plutôt envoyer la pile de comportements antérieurs (ou états précédents soyons justes) explicitement au lieu de compter sur la méthode intégrée, il BecomeStacked Akka que cache l'histoire et rend plus difficile à tester. Donc, l'absence de méthodes BecomeXXX dans F # API ne le rend pas vraiment moins puissant.

+0

Alors, vous voulez dire que ma réponse est la bonne? ;) –

+0

D'accord, d'accord. Au moins le meilleur :-) –

Répondre

1

j'ai écrit un simple échantillon de la façon dont je le résoudre en utilisant MailboxProcessor, le concept est le même que vous devriez être en mesure de traduire facilement akka.net:

type Message = 
    | Ping 
    | Back 

type State = {Behavior: State -> Message -> State; Previous: State -> Message -> State} 

let rec pong state message = 
    match message with 
    | Ping -> 
     printfn "Pong" 
     {state with Behavior = superpong} 
    | Back -> 
     {state with Behavior = state.Previous} 
and superpong state message = 
    match message with 
    | Ping -> 
     printfn "Super pong" 
     {state with Behavior = pong} 
    | Back -> 
     {state with Behavior = state.Previous} 

let agent = new MailboxProcessor<Message>(fun inbox -> 
    let setPrevious oldState newState = 
     {newState with Previous = oldState.Behavior} 
    let rec loop state = 
     async { 
      let! msg = inbox.Receive() 
      return! loop (msg |> state.Behavior state |> setPrevious state) 
     } 
    loop {Behavior = pong; Previous = pong}) 

agent.Start() 
agent.Post(Ping) 
agent.Post(Ping) 
agent.Post(Back) 
agent.Post(Ping) 
agent.Post(Ping) 

sortie est:

Pong

super pong

super pong

Pong

L'idée est que vous avez le comportement dans le cadre de l'Etat à l'agent. Notez que les fonctions doivent être définies avec la syntaxe let rec ... and ... afin que la deuxième fonction puisse renvoyer la première fonction dans un nouvel état.

La mise à jour a simplifié l'exemple avec un seul type de message.

+0

Mais qu'en est-il si en plus de "pong" et "superpong" vous avez "extrapong" et en plus de "Switch" vous avez "Back" qui vous ramène au comportement précédent? Le support de ceci est disponible dans Akka.NET C#. –

+0

En d'autres termes, ce que vous avez montré est un Akka régulier devenu, pas devenu empilé. –

+0

Pouvez-vous revenir en arrière un nombre arbitrairement d'étapes ou juste à la précédente?De toute façon, je le définirais dans le type d'état. Vous pouvez par exemple écrire 'State = {Behaviour: State -> Message -> State; Précédent: State -> Message -> State} ', puis redirige le résultat de' (état msg |> state.Behavior) 'vers quelque chose qui définit' Previous'. Mise à jour de l'exemple afin de montrer ce que je veux dire. –