sqlite - 将 ReaderT 和 runReaderT 与 SQLite 一起使用?

标签 sqlite haskell monads

我有以下代码,取自 here :

type Blog a = ReaderT SQLiteHandle IO a
data BlogDBException = BlogDBException String deriving (Show, Typeable)
instance Exception BlogDBException 

run :: Blog a -> IO a
run m = do 
  db <- openConnection "myblog.db"
  runReaderT m db --runReaderT :: ReaderT r m a -> (r -> m a)


sql :: String -> Blog (Either String[[Row Value]])
sql query = do
  db <- ask --ask :: Monad m => ReaderT r m r
  liftIO $ do
    putStrLn query
    execStatement db query


dbQuery :: Blog [Int]
dbQuery = do 
   r <- sql "select UID from UIDS;"
   case r of 
    Right [rows] -> return [fromIntegral uid | [(_, Int uid)] <- rows]
    Left s -> liftIO $ throwIO (BlogDBException s)
    _ -> liftIO $ throwIO (BlogDBException "Invalid result")

我正在尝试理解

1) readerTdata Blog a 中的确切作用?

2) runReaderT 到底在做什么?

3) ask 功能如何工作?

有没有人能简单的解释一下?这是我第一次使用 Reader monad。

最佳答案

1) 在此示例中,ReaderT 的目的是使 SQLiteHandle 类型的值可供函数使用,而无需向每个函数添加额外的参数。

2) runReaderT “解开”ReaderT:newtype ReaderT r m a = ReaderT { runReaderT::r -> m a}。正如您所看到的,真正的表示是 r -> m a:从提供的 r 类型项到您认为的 m a 的函数你直接打交道。因此,ReaderT 并没有真正避免必须向函数添加新参数的事实;它只是为你隐藏它。

3) runReaderT Ask == runReaderT $ ReaderT return == return == r -> m r 因此 ask 提供对“环境”r 的访问 (额外参数)只需将其包装在底层 monad 中即可。

这是一个非常简单(诚然太简单而不现实)的示例。

type ModeFlag = Int

g :: ModeFlag -> IO ()
g modeFlag = ... -- take some action based on modeFlag

相当于

h :: ReaderT ModeFlag IO ()
h = do
  modeFlag <- ask
  ... -- take some action based on modeFlag

当我开始学习 Haskell 时,这种技术的实用性对我来说并不是立即显而易见的。但是,请考虑您有许多配置参数的情况,或者您可能预见到需要很快添加更多配置参数。向函数添加新参数非常不方便。相反,只需将配置值打包到记录中,并通过 ReaderT 在整个应用程序中提供它。有一个名为 asks 的函数,它与 ask 类似,但也接受一个应用于 r 值的函数。这可用于从记录中提取某些字段。

data Config :: Config { param1 :: Int, param2 :: String, ... other fields }

doStuff :: ReaderT Config IO ()
doStuff = do
  i <- asks param1
  s <- asks param2
  undefined -- do some stuff

文档中还有一些 ReaderReaderT 的示例(http://hackage.haskell.org/package/mtl-2.2.1/docs/Control-Monad-Reader.html 在底部),包括 local 函数很酷,但我没用过太多。

关于sqlite - 将 ReaderT 和 runReaderT 与 SQLite 一起使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41825686/

相关文章:

macos - SQLite 代码 28 "file renamed while open"

c# - 具有多线程访问的SQLitePCLRaw.provider.e_sqlite3.dll中的System.AccessViolationException或System.ExecutionEngineException崩溃

haskell - 如何在 TemplateHaskell 引用中捕获类型变量

haskell - Haskell 中的音频和信号处理

haskell - 使用 IO monad 编写大部分代码可以吗

javascript - Node +Jade+Express+Sqlite : How can I add a MiniMap to a Leaflet Map?

sql - 选择 SQLite3 中的每第 n 行

haskell - 推断类型不够通用

functional-programming - "bind"可以对 List monad 进行减少吗?

f# - 重试 monad 和零构造