读取文件的奇怪行为

时间:2010-08-11 14:27:09

标签: parsing haskell io

我在Haskell写一个程序 这是代码

module Main
where
import IO
import Maybe
import Control.Monad.Reader
--il mio environment consiste in una lista di tuple/coppie chiave-valore
data Environment = Env {variables::[(String,String)]}deriving (Show)

fromEnvToPair :: Environment-> [(String,String)]
fromEnvToPair (Env e)= e

estrai' x d
|length x==0=[]
|otherwise=estrai x d
estrai (x:xs) d
| (x:xs)=="" =[]
| x== d=[]
| otherwise = x:(estrai  xs d)
--estrae da una stringa tutti i caratteri saino a d
conta'  x d n 
| length x==0 = 0
|otherwise = conta x d n 
conta (x:xs) d n
| x== d=n
| otherwise = (conta  xs d (n+1))
primo (a,b,c)=a
secondo (a,b,c)=b
terzo (a,b,c)=c

estraifrom x d n
|n>=(length x) =[]
| x!!n==d = []
|otherwise = x!!n:(estraifrom x d (n+1))

readerContent :: Reader Environment Environment
readerContent =do
content <- ask
return ( content)

-- resolve a template into a string
resolve :: [Char]-> Reader Environment (String)
resolve key= do
varValue <- asks (lookupVar key)
return $ maybe "" id varValue

maketuple x =(k,v,l) where
k= (estrai' x ':')--usare estrai'

v=estraifrom x ';' (conta' x ':' 1)
l= (length k)+(length v)+2 --è l'offset dovuto al; e al :
makecontext x
| length x==0 = []
| (elem ':' x)&&(elem ';' x)==False = []
|otherwise= (k,v):makecontext (drop l x) where
    t= maketuple x
    k= primo t
    v= secondo t
    l= terzo t



doRead filename = do
    bracket(openFile filename ReadMode) hClose(\h -> do 
        contents <- hGetContents h 
        return contents
        let cont=makecontext contents
        putStrLn (take 100 contents)
        return (contents))
--          putStrLn (snd (cont!!1)))
--          putStrLn (take 100 contents))


-- estrae i caratteri di una stringa dall'inizio fino al carattere di controllo
-- aggiungere parametri to the environment

-- estrae i caratteri di una stringa dall'inizio fino al carattere di controllo
-- aggiungere parametri to the environment



-- lookup a variable from the environment
lookupVar :: [Char] -> Environment -> Maybe String
lookupVar name env = lookup name (variables env)
lookup'  x t=[v| (k,v)<-t,k==x]





fromJust' :: Maybe a -> a
fromJust' (Just x) = x
fromJust' Nothing  = error "fromJust: Nothing"

main = do

file<- doRead "context.txt"-- leggo il contesto
let env= Env( makecontext file) -- lo converto in Environment
let c1= fromEnvToPair(runReader readerContent env)
putStrLn(fromJust'(lookupVar "user" env))
--putStrLn ((lookup' "user" (fromEnvToPair env))!!0)-- read the environment
--putStrLn ("user"++ (fst (c1!!1)))
putStrLn ("finito")
--putStrLn("contesto" ++ (snd(context!!1)))

我想要做的是读取格式化内容并将其放入环境中的文件,它读取文件并执行所有其他内容只有在doRead中才有行     putStrLn(取100个内容) 否则我不能拿anithing,有人知道为什么? 如果我不知道为什么,我不想离开那条线 提前致谢 提前谢谢

2 个答案:

答案 0 :(得分:0)

我认为问题是懒惰。在实际读取内容之前关闭文件句柄。通过在关闭手柄之前获取并打印一些内容,您可以在返回/关闭手柄之前强制它加载它。

我建议使用readFile中的System.IO.Strict功能。它严格加载内容(非延迟),并且还可以节省使用文件句柄的一些麻烦。您只需使用readFile替换对doRead的调用,因为它具有相同的类型签名。

答案 1 :(得分:0)

使用其中一个Haskell解析器库可以使这种事情变得更加痛苦和容易出错。以下是使用Attoparsec

执行此操作的示例
module Main where

import Control.Applicative
import qualified Data.Map as M
import Data.Attoparsec (maybeResult)
import qualified Data.Attoparsec.Char8 as A
import qualified Data.ByteString.Char8 as B

type Environment = M.Map String String

spaces = A.many $ A.char ' '

upTo delimiter = B.unpack <$> A.takeWhile (A.notInClass $ delimiter : " ")
                          <* (spaces >> A.char delimiter >> spaces)

entry = (,) <$> upTo ':' <*> upTo ';'

environment :: A.Parser Environment
environment = M.fromList <$> A.sepBy entry A.endOfLine

parseEnvironment :: B.ByteString -> Maybe Environment
parseEnvironment = maybeResult . flip A.feed B.empty . A.parse environment

如果我们有文件context.txt

user: somebody;
home: somewhere;
x: 1;
y: 2;
z: 3;

我们可以按如下方式测试解析器:

*Main> Just env <- parseEnvironment <$> B.readFile "context.txt"
*Main> print $ M.lookup "user" env
Just "somebody"
*Main> print env
fromList [("home","somewhere"),("user","somebody"),("x","1"),("y","2"),("z","3")]

请注意,我使用Map来表示环境,正如camcann在您之前的Reader monad问题的评论中所建议的那样。