2014-10-17 21 views
1

我一直在享受學習Haskell,我認爲我在這裏和#haskell的幫助下取得了一些很好的進展。我的學習大部分時間還處於觀察示例的階段,並試圖抽象出應用在那裏的技術並將其應用到我自己的代碼中。如何在monad堆棧中使用持久化?

目前,我已經開始研究開發用於各種應用程序的monad堆棧,我期待將持久框架的功能集成到我的應用程序中。

這裏是我的單子堆棧:

newtype App a = App { unApp :: StateT AppState (SqlPersistT (ResourceT (LoggingT IO))) a } 
       deriving (Applicative 
         , Functor 
         , Monad 
         , MonadIO 
         , MonadState AppState 
         ) 

AppState僅僅是一個記錄數據型保持在這個例子中一個int值。

我的主要功能是這樣的:

main = runApp "./test.sqlite" (AppState 69) runMigrate 

其中runApp應該解開所有的單子:

runApp :: Text -> AppState -> App a -> IO a 
runApp t s a = 
    runStdoutLoggingT . runResourceT . withSqliteConn t . runSqlConn . flip evalStateT s . unApp 

runMigrate是在App單子運行應用程序。在這種情況下,我在拍攝的只是得到它運行遷移:

runMigrate :: App() 
runMigrate = return $ liftPersist $ runMigration migrateAll 

編譯器指出,我不知道我該投訴做:

Main.lhs:59:16: 
    Couldn't match type ‘m0()’ with ‘()’ 
    Expected type: App() 
     Actual type: App (m0()) 
    In the expression: return $ liftPersist $ runMigration migrateAll 
    In an equation for ‘runMigrate’: 
     runMigrate = return $ liftPersist $ runMigration migrateAll 

問題:

  1. 什麼是正確的方法來做到這一點?

  2. 如果在我的monad堆棧中會引入ReaderT會發生什麼?鑑於SqlPersistT真的是ReaderT我如何確保ask與真正的ReaderT匹配,而不是SqlPersistT

回答

1

關於第一個問題:return是不正確的功能---的return的一點是,return x不關你的單子的工作,只是返回一個值。我想你可能想:

runMigrate = App $ lift $ runMigration migrateAll 

App提升您的newtype定義到您的單子; liftPersistT放入包裝StateT

(順便說一句,我建議命名爲App . lift . runMigrationrunMigrationApp如果你打算使用它了。)