如何在monad堆栈中使用persistent?

时间:2014-10-17 14:38:01

标签: haskell persistent

我一直很喜欢学习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应该解开所有monad:

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

runMigrate是在App monad中运行的应用程序。在这种情况下,我正在拍摄,只是为了让它进行迁移:

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 个答案:

答案 0 :(得分:1)

关于你的第一个问题:return不是正确的函数--- return的要点是return x没有完成monad的工作而只返回一个值。我想你可能想要:

runMigrate = App $ lift $ runMigration migrateAll

App将您的newtype定义提升到您的monad中; liftPersistT提升到包裹StateT

(顺便提一下,如果您要使用App . lift . runMigration,我建议将runMigrationApp命名为{{1}}。)