haskell - 结合持久化和 IO

标签 haskell yesod

我正在尝试递归遍历目录、处理文件并将结果存储在数据库中,但我遇到了问题。

我正在尝试做的一个简化示例如下所示:

{-# LANGUAGE QuasiQuotes, TemplateHaskell, TypeFamilies, OverloadedStrings #-}
{-# LANGUAGE GADTs, FlexibleContexts #-}
import Database.Persist
import Database.Persist.Sqlite
import Database.Persist.TH
import System.Environment (getArgs)
import System.Directory (canonicalizePath, getDirectoryContents, doesDirectoryExist, doesFileExist)
import System.FilePath (combine, takeExtension)
import Control.Monad (filterM, mapM_)
import Control.Monad.IO.Class (liftIO)

share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistUpperCase|
File                                                       
  path String
  deriving (Show)
|]
main :: IO ()
main = do
  args <- getArgs
  path <- canonicalizePath $ head args
  runSqlite "files.sqlite" $ do
    runMigration migrateAll
    liftIO $ processDirectory path
    return ()

processDirectory path = files >>= mapM_ processFile >>
                        directories >>= mapM_ processDirectory
  where contents  = getDirectoryContents path >>=
                    return . map (combine path) . filter (`notElem` [".", ".."]) 
        directories = contents >>= filterM doesDirectoryExist
        files = contents >>= filterM doesFileExist

processFile path = insert $ File path

但是上面的代码没有编译,而是导致:

No instance for (PersistStore IO)
      arising from a use of `processFile'
    Possible fix: add an instance declaration for (PersistStore IO)
    In the first argument of `mapM_', namely `processFile'
    In the second argument of `(>>=)', namely `mapM_ processFile'
    In the first argument of `(>>)', namely
      `files >>= mapM_ processFile'
Failed, modules loaded: none.

这对我来说很有意义,因为 processFile 只是对插入的调用,PersistStore monad 的哪一部分(对吗?)不是 IO。我想我需要的是一个 monad 转换器,但此时我遇到了一堵砖墙,这可能意味着我找错了树。

最佳答案

希望包含在 liftIO 中的一件事是数据库操作,因此您需要重新安排代码以将 processFile 留在外面

关于使其编译的代码的最简单更改如下。我会留给你整理它,以便更清楚发生了什么!

{-# LANGUAGE QuasiQuotes, TemplateHaskell, TypeFamilies, OverloadedStrings #-}
{-# LANGUAGE GADTs, FlexibleContexts #-}
import Database.Persist
import Database.Persist.Sqlite
import Database.Persist.TH
import System.Environment (getArgs)
import System.Directory (canonicalizePath, getDirectoryContents, doesDirectoryExist, doesFileExist)
import System.FilePath (combine, takeExtension)
import Control.Monad (filterM, mapM_)
import Control.Monad.IO.Class (liftIO)

share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistUpperCase|
File                                                       
  path String
  deriving (Show)
|]
main :: IO ()
main = do
  args <- getArgs
  path <- canonicalizePath $ head args
  runSqlite "files.sqlite" $ do
    runMigration migrateAll
    processDirectory path
    return ()

processDirectory path = liftIO files >>= mapM_ processFile >>
                        liftIO directories >>= mapM_ processDirectory
  where contents  = getDirectoryContents path >>=
                    return . map (combine path) . filter (`notElem` [".", ".."])  
        directories = contents >>= filterM doesDirectoryExist
        files = contents >>= filterM doesFileExist

processFile path = insert $ File path

关于haskell - 结合持久化和 IO,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15628980/

相关文章:

haskell - Yesod 系统要求是什么?

yesod - 如何在 Yesod 上生成 token 小部件?

mysql - Esqueleto 位于实体 ID 上

haskell - 对 Num 和 Char 值使用 Haskell 加法函数

function - Haskell 错误 - 无法匹配预期类型

javascript - 是否可以从 JavaScript 调用 hamlet?

yesod - 解析 JSON 帖子

haskell - 如何使用darcs库查询补丁信息?

haskell - 为什么这会打败 Haskell 的懒惰评估?

Haskell:在类型类中定义变量