2011-12-12 39 views
1

該應用類型類型錯誤snaplet會話

data App = App 
    { _heist  :: Snaplet (Heist App) 
    , _session  :: Snaplet SessionManager 
    } 

初始化器

... 
addRoutes [ ("/ss", companyHandler) 
      , ("", heistServe) 
      ] 
... 

處理機

companyHandler :: Handler b v() 
companyHandler = method GET getter <|> method POST setter 
    where 
    getter = do 
     value <- getFromSession "name" 
     writeText $ fromMaybe "nothing" value 
    setter = do 
     mname <- getParam "name" 
     setInSession "name" (convert mname) 
     getter 
    convert = T.pack . B.unpack . (fromMaybe "nothing") 

heistServe的具有類型Handler b (Heist b)()

鍵入e RROR:

src/Tutorial.hs:50:52: 
    Couldn't match type `v' with `SessionManager' 
     `v' is a rigid type variable bound by 
      the type signature for companyHandler :: Handler b v() 
      at src/Tutorial.hs:50:1 
    Expected type: Handler b v() 
     Actual type: Handler b SessionManager() 
    In the second argument of `method', namely `setter' 
    In the second argument of `(<|>)', namely `method POST setter' 

回答

3

你必須綁定你SessionManager到處理程序的情況下才可以使用其上運行的功能。這是通過做:

withTop session $ setInSession "name" (convert mname) 
-- Where session is the generated lens for your snaplet 

如果你也想在事後提交您的會話(因爲你改變了會話,不只是看一個變量),您需要:

withSession . withTop session $ ... 

如果您下面的代碼添加到您的主應用程序的snaplet初始化代碼,你不必擔心在提交所有會議,因爲它是自動完成的:解決次

wrapHandlers withSession 
+0

它不起作用。 'sessionSession'$ setInSession'name'(convert mname):: Handler b SessionManager()',用於'setInSession :: Text - > Text - > Handler b SessionManager()' – wenlong

+0

對不起,我沒有測試過代碼,我應該這樣做。看起來,會話API是以奇怪的方式構建的;你需要使用'withTop'而不是'withSession'。如果你使用Session。 withTop session $ ...',它會爲你做的是在完成之後提交會話。 – dflemstr

+0

它編譯,但會話不會在請求之間共享。完整的代碼是[在這裏使用](https://gist.github.com/1471406/547b13d5603a12090df2d2ad3fb7fd124ce3619e)和[在這裏使用withSession和withTop](https://gist.github.com/1471406/082e20e0a217255d52d79a770bc3ebdf554d578c) – wenlong

0

的一種方式e問題與以下行:

companyHandler = with session $ method GET getter <|> method POST setter 

我覺得有幫助的另一件事是專門化我的應用程序的類型簽名。在這種情況下,新型的簽名是:

companyHandler :: Handler App App() 

你們中的大多數都不會寫通用代碼應該是跨多個應用程序重複使用的時候,所以一般性的小損失這裏不會傷害你。具有更多具體類型的簽名通常會使錯誤消息更容易解密,這對於編譯代碼會有很大的幫助。即使我編寫的代碼應該是所有應用程序/ snaplets中的通用代碼,但有時我仍然覺得從更具體的類型開始,然後在得到它的工作後推廣是有幫助的。

dflemstr有關Session的說法是正確的。我通常喜歡在一切事情上做一次,而不是把它放在setInSession的調用上,但是你應該做適合你的應用的任何事情。