2012-01-13 82 views
2

Snap Framework中,Snaplets用於通過基於組件的接口將功能嵌入到其他Snaplets中:主Web應用程序是一個Snaplet,通過經典的「has-a」關係引用其他Snaplet ,而子Snaplets可以參考其他Snaplets。引用子Snaplets的首選方法

在研究各種Snaplet實現時,我看到了使用不同的模式將Snaplet嵌入到父Snaplet中。具體來說:

  • 參考的種類。 Snaplet實現假定存在與父Snaplet的特定類型的關係。這是通過參考方法強制使用(見下文)。

    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. 每次調用操作Snaplet的函數時,數據都存在於MonadState中。
    2. 數據存在於MonadState中,幷包裹在Snaplet包裝中。
    3. 有一個+ instance HasSubSnaplet MySnaplet類的實例,它具有從MySnaplet中獲取Snaplet數據的功能,前提是MySnaplet在調用該函數時位於MonadState中。
    4. 3.中的函數代替了MySnaplet -> Snaplet SubSnaplet
    5. 在3.中有一個類+實例,它提供了一個Lens MySnaplet (Snaplet SubSnaplet)
    6. 類+實例需要Lens (Snaplet MySnaplet) (Snaplet SubSnaplet)
    7. 類+實例假設MySnaplet是應用程序的「最高Snaplet」,並且需要絕對鏡頭/參考,因此MySnaplet必須是b中的MonadSnaplet

在我看來,那種參考1.有道理的,如果在Snaplet是隻讀的,和2有道理,如果Snaplet需要改變。

此外,具有用於該方法的類有意義時MySnaplet只能有一個SubSnaplet並沒有更多,和具有絕對基準可能是有意義的事情等的數據庫,其不可能被配置作爲一個組件,因爲只頂級的Snaplet可以訪問憑據,而不是。但是,將這個假設作爲Snaplet作者可能是錯誤的,並且使用相對引用不會有什麼不利。

雖然有一個proglem:Hackage上的現有Snaplets不符合我所做的這些假設;上面描述的所有方法看起來都是隨機的,在各種情況下都可以使用。另外,我認爲上述其他方面沒有優勢/劣勢(例如需要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國家-Class.html)? – ehird 2012-01-13 15:15:56

+0

@ehird對,我太習慣說「The State' monad」 – dflemstr 2012-01-13 15:27:58

+0

我不確定你說的「一噸不同的方法是什麼」。我們使用了最適合這種情況的任何方法。 – mightybyte 2012-01-20 21:43:56

回答

1

TLDR;大多數情況下,您可能需要使用with功能和相關鏡頭。

HasSubsnaplet類型類的使用是一個完全可選的模式,它可以減少「with subSnaplet」樣板,如果它有多個SubSnaplet實例沒有意義。我們選擇爲捕捉包中的Heist snaplet做到這一點,因爲它對Heist snaplet有意義,併爲用戶提供了一個模式示例。

由於類型類是完全可選的,並且與透鏡的選擇大致正交,對於本答案的其餘部分,我將重點討論如何在沒有類型類的情況下進行操作。

該API的目的是使用透鏡(而不是「簡單引用」,可以讓你的東西包裝在Snaplet數據類型中)來訪問你的狀態。這是因爲在請求處理過程中變更狀態是我們希望Snaplets提供的基本功能。在大多數情況下,我們打算將Snaplet作爲一個不透明的包裝,最終用戶除了在其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產生並且是最自然的使用透鏡。因此,這是推薦的模式。 (因此較短的未引發名稱。)withwithTop之間的區別在於with拍攝了一個相對鏡頭,而withTop拍攝了一個絕對鏡頭。大多數時候我使用相對鏡頭。但我們希望允許使用絕對鏡頭,因爲我可以想象複雜的應用程序,其中一個可能需要另一個零件提供的東西,但不是當前零件的後代。

偶爾會出現您希望能夠擁有身份鏡頭的情況。這需要一個Lens (Snaplet a) (Snaplet b)。因此,除了他們採用這種鏡頭之外,第二個引發的功能與前兩個類似。

相關問題