странное поведение при чтении файла - PullRequest
1 голос
/ 11 августа 2010

Я пишу программу на Хаскеле вот это код

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

Что я хочу сделать, так это прочитать файл, форматирующий содержимое, и поместить его в Environment, хорошо, он читает файл и выполняет все остальные действия, только если в doRead есть строка putStrLn (взять 100 содержимого) в противном случае я не могу взять anithing, кто-нибудь знает почему? Я не хочу покидать эту линию, если я не знаю, почему заранее спасибо заранее спасибо

Ответы [ 2 ]

0 голосов
/ 12 августа 2010

Использование одной из библиотек анализатора 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 вопросу о монаде.

0 голосов
/ 11 августа 2010

Я думаю, что проблема в лени.Дескриптор файла закрывается до того, как этот контент действительно будет прочитан.Взяв и напечатав часть содержимого перед закрытием дескриптора, вы заставляете его загрузить его перед возвратом / закрытием дескриптора.

Я предлагаю использовать функцию readFile из System.IO.Strict.Он загружает содержимое строго (не лениво), а также избавляет от некоторых трудностей при работе с файловыми дескрипторами.Вы просто заменяете вызов doRead на readFile, так как он имеет такую ​​же сигнатуру типа.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...