2012-10-02 105 views
1

試圖在Snap中使用酸性狀態,並且遇到了障礙。Snap,IO和酸性狀態

這是我到目前爲止。

首先我酸性狀態相關的對象(這是一個假書有ISBN號):

{-# LANGUAGE DeriveDataTypeable   #-} 
{-# LANGUAGE GeneralizedNewtypeDeriving #-} 
{-# LANGUAGE MultiParamTypeClasses  #-} 
{-# LANGUAGE TemplateHaskell   #-} 
{-# LANGUAGE TypeFamilies    #-} 
{-# LANGUAGE OverloadedStrings   #-} 

module Models where 

import Prelude hiding ((.), id) 
import Control.Category ((.)) 
import Control.Monad.Reader (asks) 
import Data.ByteString (ByteString) 
import Data.SafeCopy (base, deriveSafeCopy) 
import qualified Data.Text as T 
import Data.Typeable (Typeable) 
import Data.Acid (Update, Query, makeAcidic) 
import Control.Monad.Reader (ask) 
import Control.Applicative ((<$>)) 
import Data.Data (Data) 

data Book = Book { isbn :: String } 
    deriving (Eq, Ord, Read, Data, Show, Typeable) 

$(deriveSafeCopy 0 'base ''Book) 

-- Retrieve the book's isbn 
queryIsbn :: Query Book String 
queryIsbn = isbn <$> ask 

$(makeAcidic ''Book ['queryIsbn]) 

然後我在用捕捉它整合實際的嘗試。正如你所看到的,我有定義__ doQuery__功能的麻煩,應該返回一個字符串ISBN:

{-# LANGUAGE TemplateHaskell #-} 
{-# LANGUAGE OverloadedStrings #-} 
module Application where 

import   Control.Monad.Trans.Class (lift) 
import   Data.Text.Encoding (decodeUtf8) 
import   Text.XmlHtml (Node(TextNode),Node (Element), 
       getAttribute, setAttribute, nodeText) 
import   Data.ByteString (ByteString) 
import   Data.Maybe 
import   Snap.Core 
import   Snap.Snaplet 
import   Snap.Snaplet.Heist (Heist, HasHeist(heistLens), heistInit, 
         addSplices, liftHeist, render) 
import   Snap.Util.FileServe 
import   Text.Templating.Heist (HeistT, Template, getParamNode) 
import   Data.Lens.Template 

import Models 
import Data.Acid.Advanced (query') 
import Data.Acid (AcidState, openLocalState, closeAcidState, IsAcidic, query) 
import Data.Text (pack) 
import Control.Monad.IO.Class (liftIO, MonadIO) 
import Snap (snapletValue) 
import Data.Lens.Common (getL, (^$), (^.), Lens) 
import Control.Monad.Reader (ask, asks) 
import Control.Applicative ((<$>)) 
import Data.Typeable (typeOf) 


import Prelude hiding ((.), id) 
import Control.Category ((.), id) 

------------------------------------------------------------------------------ 
type AppHandler = Handler App App 

-------------- 
-- Acid 
--------------- 
-- Used for holding data for the snapplet 
data Acid st = Acid { _state :: AcidState st } 

-- Initializer function for the snapplet 
seedBook = Book "9213-23123-2311" 

acidInit :: SnapletInit b (Acid Book) 
acidInit = makeSnaplet "storage" "Snaplet providing storage functionality" Nothing initializer 

--The 'm' is the type variable of the MonadSnaplet type class. 'b' is the base state, and 'v' is the state of the current "view" snaplet (or simply, current state). 
initializer :: Initializer b v (Acid Book) 
initializer = do 
     st <- liftIO (openLocalState seedBook) 

     --onUnload (closeAcidState st) 
     return $ Acid st 

----------------------- 
-- Snap Global State 
-------------------- 

data App = App 
    { _heist :: Snaplet (Heist App), 
     _acid :: Snaplet (Acid Book) 
    } 

makeLens ''App 
---------------------------------------------------------------------------------- 

instance HasHeist App where 
    heistLens = subSnaplet heist 

----------------------------------------------- 
-- | Initialize app 
----------------------------------------------- 
appInit :: SnapletInit App App 
appInit = makeSnaplet "app" "Website" Nothing $ do 
    h <- nestSnaplet "" heist $ heistInit "templates" 
    a <- nestSnaplet "isbn" acid (acidInit) 
    addRoutes routes --see below 
    addSplices [ ("menuEntry", liftHeist menuEntrySplice) ] 
    return $ App h a 


------------------------------------------------ 
-- | The application's routes. 
------------------------------------------------ 
routes :: [(ByteString, Handler App App())] 
routes = [ ("/books", handleBooks) 
     , ("/contact", render "contact") 
     , ("/isbn",  liftIO doQuery >>= writeBS) 
     , ("",   serveDirectory "static") 
     ] 

-- Is this Function signature possible? Or must it run inside Snap or other monad? 
doQuery :: IO ByteString 
doQuery = do -- ??????????? 
     --somehow retrieve acid store from snaplet 
     --run queryIsbn on it 
     --return isbn string 
     return "BLAH" 


handleBooks :: Handler App App() 
handleBooks = render "books" 

對我缺少的是什麼任何幫助將不勝感激。如果有問題不清楚,請讓我知道,我會更新問題。

回答

0

我不知道你使用的軟件包的想法,但它看起來這個問題很簡單,openLocalStateIO動作,但你的類型的簽名要求它是一個Initializer行動。

解決這個問題可能很簡單,只需填寫電話liftIO即可。我不確定,但是......我不知道這些類型中的哪一個來自哪個模塊。

+0

嘿,感謝您的幫助。我已將所有導入添加到問題中,請告知我是否有幫助。在此期間我會嘗試'liftIO'。 – drozzy

1

MathematicalOrchid是正確的,對您的問題最簡單的答案是在openLocalState調用上使用liftIO。

但是從更廣泛的角度來看,你在這裏做的事情已經由snaplet-acid-state包完成了,所以我建議你只使用它。該存儲庫還包含一個演示如何使用它的example application

+0

嗨mightybyte,謝謝你的建議。我實際上是遵循着snaplet-acid-state snaplet--我只是想不帶它(僅使用酸態)來理解封面下發生了什麼。此外,它還使用了一個較舊的酸性包裝:-( – drozzy

+0

snaplet-acid-state [使用liftIO](https://github.com/mightybyte/snaplet-acid-state/blob/master/src/Snap/Snaplet/ AcidState.hs#L79)。我也上傳了一個新版本hackage,允許最新版本的酸態。 – mightybyte

+0

謝謝,我想到了初始化函數!你能看看我修改過的代碼嗎?特別是,我不確定你的代碼如何從snaplet('doQuery'函數)獲取酸狀對象,你可以通過類來實現,但是我想嘗試去理解它,而不需要類。 – drozzy