2

ディレクトリを再帰的に処理し、ファイルを処理して結果をデータベースに保存しようとしていますが、問題が発生しています。

私がやろうとしていることの簡単な例は次のようになります。

{-# 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は単にinsertの呼び出しであり、PersistStoreモナドのどの部分(右?)はIOではないので、これは私には理にかなっています。必要なのはモナド変換子だと思いますが、この時点でレンガの壁にぶつかっています。これはおそらく、間違った木を吠えていることを意味します。

4

1 に答える 1

7

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
于 2013-03-26T09:15:23.853 に答える