2012-01-13 1 views
2

В Snap Framework, Snaplets используются для встраивания функциональности в другие Snaplets через компонентный интерфейс: Основное веб-приложение представляет собой Snaplet, который ссылается на другие Snaplets с помощью классического отношения «has-a» , и суб-Snaplets могут, в свою очередь, ссылаться на другие Snaplets.Предпочтительный метод для привязки суб-привязок

При просмотре различных реализаций Snaplet я видел различные шаблоны, используемые для встраивания Snaplet в родительский Snaplet. В частности:

  • Вид ссылки. Реализация Snaplet предполагает, что существует определенный вид отношения к родительскому Snaplet. Это применяется с использованием метода Reference (см. Ниже).

    1. Простая ссылка:

      data MySnaplet = MySnaplet { subSnaplet :: Snaplet SubSnaplet } 
      
    2. Относительный линзы:

      data MySnaplet = MySnaplet { _subSnaplet :: Snaplet SubSnaplet } 
      
      subSnaplet :: Lens MySnaplet SubSnaplet 
      subSnaplet = lens _subSnaplet $ \ a b -> a { _subSnaplet = b } 
      
  • Контрольный метод. Реализация Snaplet обеспечивает через свой интерфейс конкретный способ доступа к данным Snaplet, а различные реализации Snaplet используют разные методы. Snaplet предполагает, что:

    1. Данные присутствуют в MonadState каждый раз, когда вызывается функция, управляющая Snaplet.
    2. Данные представлены в MonadState и завернуты в обертку Snaplet.
    3. Существует класс + экземпляр как instance HasSubSnaplet MySnaplet, который имеет функцию для получения данных Snaplet выхода из MySnaplet при условии, что MySnaplet находится в MonadState в точке вызова функции.
    4. Функция в 3. имеет тип MySnaplet -> Snaplet SubSnaplet вместо.
    5. Существует экземпляр класса +, например, в 3., который предоставляет Lens MySnaplet (Snaplet SubSnaplet).
    6. Для экземпляра класса + требуется Lens (Snaplet MySnaplet) (Snaplet SubSnaplet).
    7. Класс + экземпляр предполагает, что MySnaplet является «сверху Snaplet» приложения, и требует абсолютного объектива/ссылка, таким образом, что MySnaplet должен быть в MonadSnapletb.

Как я это вижу, ссылка вид 1. имеет смысл, если Snaplet только для чтения, и 2. имеет смысл, если Snaplet необходимо изменить.

Кроме того, имея класс для метода имеет смысл, когда MySnaplet может иметь только один SubSnaplet и не более, и с абсолютной ссылка может иметь смысл для таких вещей, как базы данных, что не может быть настроена в качестве компонента, учитывая, что только верхний Snaplet имеет доступ к учетным данным, а что нет. Однако принятие этого предположения как писателя Snaplet может быть ошибочным, и вместо этого не было бы никаких недостатков в использовании относительных ссылок.

Существует один прогмм: Существующие привязки к Hackage не соответствуют этим предположениям, которые я делаю; все описанные выше методы используются, по-видимому, случайным образом и при любых обстоятельствах. Кроме того, я не вижу преимуществ/недостатков для некоторых других аспектов, описанных выше (таких как требование обертки Snaplet, или нет).

Для меня, ссылочный вид 2. и один из методов 1, 2, 5 или 6, кажется, имеют наибольший смысл под всех обстоятельств, и я не вижу причин, по которым не существует консенсуса только с использованием, например, (2, 1) все время.

Итак:

Как писатель Snaplet, какой метод должен быть предпочтительным при написании нового Snaplet (при условии, что он имеет общее назначение), и

Что является причиной, почему все Snaplets в существовании еще не используется один и тот же ссылочный метод (даже в ядре snap пакет используется тонна различных методов)?

+0

Я не знаком с Snap, но 'StateMonad' должен быть [' MonadState'] (http://hackage.haskell.org/packages/archive/mtl/2.0.1.0/doc/html/Control -Monad-State-Class.html)? – ehird

+0

@ehird right, я слишком привык говорить «Монада государства» – dflemstr

+0

Я не совсем уверен, что вы имеете в виду, когда говорите «тонна различных методов». Мы использовали любой метод, наиболее подходящий для ситуации. – mightybyte

ответ

1

TLDR; Большую часть времени вы, вероятно, хотите использовать функцию with и относительные линзы.

Использование класса типа HasSubSnaplet является полностью необязательным шаблоном, который может сгладить шаблон с помощью поднабора «subSnaplet» в ситуациях, когда нет смысла иметь более одного экземпляра SubSnaplet. Мы решили сделать это для оснастки Heist, которая поставляется в пакетном оснастке, потому что это имеет смысл для оснастки Heist и предоставляет пользователям пример шаблона.

Поскольку тип типа полностью необязателен и примерно ортогонален выбору объектива, для остальной части этого ответа я сосредоточусь на том, что делать без класса типа.

Целью API является то, что вы используете объективы (а не «простые ссылки», которые принесут вам что-то, завернутое в тип данных Snaplet), чтобы получить доступ к вашему состоянию. Это связано с тем, что состояние мутирования во время обработки запроса является фундаментальной способностью, которую мы хотели получить Snaplets. По большей части мы предполагали, что Snaplet является непрозрачной оболочкой, которую конечный пользователь не должен касаться, кроме как в типе состояния привязки. Вот почему экземпляр MonadState приводит вас непосредственно к вашему типу без оболочки Snaplet.

С учетом сказанного существует четыре основных шаблона доступа. Мы видим, что они смотрят на 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 

Узор линзы воплощено в первых двух функций является вид линз, которые создаются для вас автоматически с помощью пакета данных линз шаблон с TemplateHaskell и являются наиболее естественным использовать. Поэтому это рекомендуемая модель. (Следовательно, более короткое, незапущенное название.) Разница между with и withTop заключается в том, что with принимает относительную линзу, а withTop принимает абсолютную линзу. Большую часть времени я использую относительные линзы. Но мы хотели разрешить использование абсолютных линз, потому что я могу представить сложные приложения, в которых одна операционная система могла бы получить что-то, предоставленное другой привязкой, но не являющуюся потомком текущей привязки.

Иногда бывают ситуации, когда вы хотите иметь идентичный объектив. Для этого требуется Lens (Snaplet a) (Snaplet b). Таким образом, две две загрунтованные функции аналогичны первым двум, за исключением того, что они принимают этот вид объектива.