2017-04-20 6 views
0

このビットはディレクトリを読み取り、すべての.iniファイル名をリストに入れます。次に、各ファイルを読み込んで解析し、解析結果とファイル名をマップに配置します(Key = filename、contents = parsed result-Config)。私の質問は、rslt <- parseFromFile parseIni fnをタイプシグネチャgetIniに適合させるにはどうすればいいですか? parseFromFileはタイプシグネチャmonad m => m (Maybe Config)であり、適合しません。また、誰かがより良いコーディング方法を提案できますか?私はrelaventコードのみをここに含めた。問題の機能はmaingetIniです。タイプシグネチャの競合

import System.FilePath.Glob (globDir, compile) 
import Control.Monad.IO.Class 
import Data.Map (Map) 
import qualified Data.Map as M 
import Data.ByteString (ByteString) 
import Control.Applicative 
import Text.Trifecta 

fPath = "c:/users/tyrone/myprojects/chp29" 

type FileName = String 
type Name = String 
type Value = String 
type Assignments = Map Name Value 

newtype Header = Header String deriving (Eq, Ord, Show) 

data Section = Section Header Assignments deriving (Eq, Show) 

newtype Config = Config (Map Header Assignments) deriving (Eq, Show) 

parseIni :: Parser Config 
parseIni = do 
    sections <- some parseSection 
    let mapOfSections = foldr rollup M.empty sections 
    return $ Config mapOfSections 

getIni :: FileName -> Map FileName Config -> Map FileName Config 
getIni fn mp = do 
    rslt <- parseFromFile parseIni fn 
    case rslt of 
    Nothing -> M.empty 
    Just confg -> do let ky = tail $ dropWhile (/= '\\') fn 
        M.insert ky confg mp 

main :: IO() 
main = do 
    iniF <- (concat . fst) <$> globDir [compile "*.ini"] fPath 
    print $ foldr getIni M.empty iniF 

答えて

1

表現parseFromFileおそらくタイプIO (Maybe Config)をので、(私はそれがファイルの内容を読み取るためにIOを行うために必要とするのオフにこれを基づか、そしてあなたのケース式がちょうど何も上で一致しているという事実だ)していますgetIniで使用する場合は、IOのタイプを返す必要があります。おそらくIO (Map FileName Config)のようなものです。これはmainでそれを使用するよりその後

getIni :: FileName -> Map FileName Config -> IO (Map FileName Config) 
getIni fn mp = do 
    rslt <- parseFromFile parseIni fn 
    case rslt of 
     Nothing -> return M.empty 
     Just confg -> do 
      let ky = tail $ dropWhile (/= '\\') fn 
      return $ M.insert ky confg mp 

ようgetIni表情になるだろう、あなたの代わりに純粋なfoldrのモナド倍を使用しなければならないでしょう。また、構文解析エラーが既に解析済みのファイルをすべて消去するので、代わりにNothing -> return mpが必要です。

また、M.mapM.filterのような純粋な関数を使用してMap FileName Configに変換すると、ファイル名を内容にマッピングするMap FileName Stringを構築することができます。私はこのコードのいずれかをコンパイルしていないが、それはあなたを与える必要があります。でも、あなたが

parseIniFiles :: Map FileName String -> (Map FileName ParseError, Map FileName Config) 
parseIniFiles contentMap = M.mapEither (parse parseIni "ini") contentMap 

そして、あなたのmainは(

main = do 
    iniF <- (concat . fst) <$> globDir [compile "*.ini"] fPath 
    contentMap <- M.fromList <$> do 
     contents <- mapM readFile iniF 
     -- As an aside, there is a better way to get the stem of the file path 
     -- Go look for a function that will split file paths into their components 
     return (tail $ dropWhile (/= '\\') fn, contents) 
    let (invalidFiles, validFiles) = parseIniFiles contentMap 
    putStrLn "Valid files" 
    print validFiles 
    putStrLn "Invalid Files" 
    print invalidFiles 

ようになり免責事項を行うことができるようになるData.Map内の機能があります一般的なアイデア)

+0

ありがとう。私はfoldrをfoldMに置き換え、パラメータを変更してシグネチャをビットで回してみました。あなたの代わりの解決策を見ていないが、できるだけ早くそうするだろう。 – user1897830