2010-08-11 75 views
1

我在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))) 

我想要做的就是讀取文件在格式化的內容和環境puting它,以及它閱讀文件,並做所有其他的東西,只有在doRead有 putStrLn(取100內容) 否則我不能拿信,有人知道爲什麼嗎? 我不想離開那一行,如果我不知道爲什麼 在此先感謝 在此先感謝

回答

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問題的評論中所建議的那樣。

0

我認爲問題是懶惰。文件句柄在實際讀取內容之前關閉。通過在關閉手柄之前拍攝並打印一些內容,您可以在返回/關閉手柄之前強制它加載它。

我建議使用System.IO.StrictreadFile函數。它嚴格加載內容(非惰性),並且還可以節省處理文件句柄的一些麻煩。您只需使用readFile將調用替換爲doRead,因爲它具有相同的類型簽名。