2012-01-13 2 views
2

Dans le Snap Framework, Snaplets sont utilisés pour incorporer la fonctionnalité dans d'autres Snaplets par l'intermédiaire d'une interface à base de composants: La principale application web est un Snaplet qui référence d'autres Snaplets par l'intermédiaire d'un classique « a-a » relation , et les sous-Snaplets peuvent à leur tour faire référence à d'autres Snaplets.procédé préféré pour faire référence à la sous-Snaplets

En examinant diverses implémentations de Snaplet, j'ai vu différents modèles utilisés pour intégrer un Snaplet dans un Snaplet parent. Spécifiquement:

  • Type de référence. L'implémentation de Snaplet suppose qu'un type spécifique de relation au Snaplet parent est présent. Ceci est appliqué via la méthode de référence utilisée (voir ci-dessous).

    1. Une référence simple:

      data MySnaplet = MySnaplet { subSnaplet :: Snaplet SubSnaplet } 
      
    2. Une lentille relative:

      data MySnaplet = MySnaplet { _subSnaplet :: Snaplet SubSnaplet } 
      
      subSnaplet :: Lens MySnaplet SubSnaplet 
      subSnaplet = lens _subSnaplet $ \ a b -> a { _subSnaplet = b } 
      
  • Méthode de référence. L'implémentation de Snaplet impose, via son interface, qu'un mode spécifique d'accès aux données Snaplet est en place, et différentes implémentations Snaplet utilisent des méthodes différentes. Le Snaplet suppose que:

    1. Les données sont présentes dans un MonadState chaque fois une fonction qui manipule le Snaplet est appelé. Les données sont présentes dans un MonadState et enveloppées dans un emballage Snaplet.
    2. Il y a une classe + comme par exemple instance HasSubSnaplet MySnaplet qui a une fonction pour obtenir les données Snaplet sur MySnaplet à condition qu'un MySnaplet est dans un MonadState au point d'appeler la fonction.
    3. La fonction dans 3. a le type MySnaplet -> Snaplet SubSnaplet à la place.
    4. Il existe une instance de classe + comme dans 3. qui fournit un Lens MySnaplet (Snaplet SubSnaplet).
    5. L'instance class + requiert un Lens (Snaplet MySnaplet) (Snaplet SubSnaplet).
    6. La classe + exemple suppose que MySnaplet est le « top Snaplet » de l'application, et nécessite une lentille/référence absolue, de sorte que MySnaplet doit être le b dans un MonadSnaplet.

Comme je le vois, référence type 1. est logique si le Snaplet est en lecture seule, et 2. est logique si le Snaplet doit changer.

De plus, ayant une classe pour la méthode est logique quand MySnaplet peut avoir qu'un seul SubSnaplet et plus, et ayant une référence absolue pourrait être logique pour des choses comme les bases de données, qui ne peuvent éventuellement être configurés en tant que composant, étant donné que seulement le top Snaplet a accès aux informations d'identification et quoi d'autre. Cependant, faire de cette hypothèse un auteur de Snaplet peut être fallacieux, et il n'y aurait aucun inconvénient à utiliser une référence relative à la place.

Il y a un proglem, cependant: Les Snaplets existants sur le Hackage ne correspondent pas à ces hypothèses que je fais; toutes les méthodes décrites ci-dessus sont utilisées apparemment au hasard et dans toutes sortes de circonstances. En outre, je ne vois aucun avantage/inconvénient à certains des autres aspects décrits ci-dessus (comme nécessitant un emballage Snaplet, ou non). Pour moi, le type de référence 2. et l'une des méthodes 1, 2, 5 ou 6 semblent les plus logiques sous toutes circonstances, et je ne vois aucune raison pour laquelle il n'y a pas consensus sur l'utilisation par ex. (2, 1) tout le temps.

Alors:

En tant qu'auteur Snaplet, ce procédé doit être préféré lors de l'écriture d'un nouveau Snaplet (en supposant qu'il a un but général), et

Quelle est la raison pour laquelle tous les Snaplets en existence ne pas déjà utiliser la même méthode de référence (Même dans le paquet de base snap, une tonne de méthodes différentes sont utilisées)?

+0

Je ne suis pas expérimenté avec Snap, mais 'StateMonad' est censé être [' MonadState'] (http://hackage.haskell.org/packages/archive/mtl/2.0.1.0/doc/html/Control -Monad-State-Class.html)? – ehird

+0

@ehird droite, je suis trop habitué à dire "La monade' 'State'" – dflemstr

+0

Je ne suis pas sûr exactement ce que vous faites référence à quand vous dites "une tonne de différentes méthodes sont utilisées". Nous avons utilisé la méthode la plus appropriée à la situation. – mightybyte

Répondre

1

TLDR; La plupart du temps, vous voulez probablement utiliser la fonction with et les lentilles relatives. L'utilisation d'une classe de type HasSubSnaplet est un modèle complètement optionnel qui peut réduire la condition standard "avec subSnaplet" dans les situations où il n'est pas logique d'avoir plus d'une instance de SubSnaplet. Nous avons choisi de faire cela pour le snaplet Heist qui est livré dans le paquet snap car cela a du sens pour le snaplet Heist et fournit aux utilisateurs un exemple du modèle.

Puisque la classe de type est complètement optionnelle et grossièrement orthogonale au choix de l'objectif, pour le reste de cette réponse, je vais me concentrer sur ce qu'il faut faire sans la classe de type.

L'intention de l'API est que vous utilisiez des objectifs (et non des «références simples» qui vous permettent d'obtenir quelque chose enveloppé dans le type de données Snaplet) pour accéder à votre état. C'est parce que l'état de mutation au cours du traitement de la requête est une capacité fondamentale que nous voulions que Snaplets fournisse. Pour la plupart, nous voulions que Snaplet soit un wrapper opaque que l'utilisateur final n'a pas besoin de toucher sauf dans le type d'état de son snaplet. C'est pourquoi l'instance MonadState vous dirige directement vers votre type sans le wrapper Snaplet. Cela dit, il existe quatre modèles d'accès de base. Nous pouvons voir ceux-ci en regardant le MonadSnaplet type class.

with  :: Lens  v  (Snaplet v') -> m b v' a -> m b v a 
withTop :: Lens  b  (Snaplet v') -> m b v' a -> m b v a 
with' :: Lens (Snaplet v) (Snaplet v') -> m b v' a -> m b v a 
withTop' :: Lens (Snaplet b) (Snaplet v') -> m b v' a -> m b v a 

Le motif de la lentille incorporée dans les deux premières fonctions est le genre de lentilles qui sont générés automatiquement pour vous par le paquet de données de lentille de modèle avec TemplateHaskell et qui sont le plus naturel à utiliser. Par conséquent, c'est le modèle recommandé. (D'où le nom plus court, non amorcé.) La différence entre with et withTop est que with prend une lentille relative et withTop prend un objectif absolu. La plupart du temps, j'utilise des lentilles relatives. Mais nous voulions permettre l'utilisation de lentilles absolues parce que je peux imaginer des applications complexes où un snaplet pourrait avoir besoin de quelque chose fourni par un autre snaplet, mais qui n'est pas un descendant du snaplet actuel.

Occasionnellement, il y a des situations où vous voulez être capable d'avoir une lentille d'identité. Cela nécessite un Lens (Snaplet a) (Snaplet b). Donc, les deux autres fonctions amorcées sont analogues aux deux premières sauf qu'elles prennent ce type de lentille.

Questions connexes