I would like to use hGetContents just to retrieve the list of the lines of a file, but if I code a function like: linesFromFile :: FilePath -> IO [String] linesFromFile f = do h <- openFile f ReadMode l <- hGetContents h hClose h return (lines l) I obviously always get the empty list as a result. How should I code the function? Vincenzo -- Teatri vuoti e inutili potrebbero affollarsi se tu ti proponessi di recitare te [CCCP]
| I would like to use hGetContents just to retrieve the list of | the lines of a file, but if I code a function like: | | linesFromFile :: FilePath -> IO [String] | linesFromFile f = do | h <- openFile f ReadMode | l <- hGetContents h | hClose h | return (lines l) | | I obviously always get the empty list as a result. How should | I code the function? Try the following: linesFromFile :: FilePath -> IO [String] linesFromFile = fmap lines . readFile All the best, Mark
On Sun, 19 Jan 2003 08:51:31 -0800 "Mark P Jones" <mpj@cse.ogi.edu> wrote:
linesFromFile = fmap lines . readFile
Nice :) BTW, is readFile implemented with some strict evaluation construct ? I got another trouble: I need to build a record type like Package { name :: String, version :: Int , mantainer :: String ... other fields ... } from a list of string of the form ["Package: ..." , "Mantainer: ..." , "Version: ..." , ... ] where the fields are not bound to be in a particular order, except for Package wich is always the first of a record. The natural solution in this case seems to be a mutable record, and an iteration over the list. Has someone got ideas? This appear to be a particularly difficult problem in haskell and it should not be. V. PS: I've just noticed that by mistake I posted on haskell and not haskell-cafe. Sorry for the inconvenience, now I end the thread here but I will not post other newbie questions here. -- Teatri vuoti e inutili potrebbero affollarsi se tu ti proponessi di recitare te [CCCP]
On Sun, 19 Jan 2003, Nick Name wrote:
I got another trouble: I need to build a record type like
Package { name :: String, version :: Int , mantainer :: String ... other fields ... }
from a list of string of the form
["Package: ..." , "Mantainer: ..." , "Version: ..." , ... ]
where the fields are not bound to be in a particular order, except for Package wich is always the first of a record.
The natural solution in this case seems to be a mutable record, and an iteration over the list. Has someone got ideas? This appear to be a particularly difficult problem in haskell and it should not be.
V.
Here's one way to do it: module ReadRecord where import Maybe (isJust) data Package = Package { name :: Maybe String, version :: Maybe Int, maintainer :: Maybe String } deriving Show parsePackage :: [String] -> Package parsePackage = foldl (parseItem trials) (Package Nothing Nothing Nothing) where parseItem (f:fs) p s = maybe (parseItem fs p s) id (f p s) parseItem [] _ s = error $ "can't match " ++ show s trials = [ try "Package" (ij.name) (\ p v -> p{name = Just v}), try "Version" (ij.version) (\ p v -> p{version = Just $ read v}), try "Maintainer" (ij.maintainer) (\ p v -> p{maintainer = Just v}) ] try key tester setter pkg str = fmap parse $ match (key ++ ": ") str where parse text = if tester pkg then error $ "duplicate field: " ++ key else setter pkg text match want str = if want == pre then Just post else Nothing where (pre, post) = splitAt (length want) str ij = isJust main = mapM_ try goods try = print . parsePackage goods = [ [], ["Package: p1", "Version: 1", "Maintainer: m1"], ["Maintainer: m2", "Package: p2"] ] bad1 = ["Version: v-b1", "Foo: foo-b1"] bad2 = ["Maintainer: me", "Maintainer: me"] bad3 = ["Version: foo"] -- Dean
I was unhappy with the use of `error` in my first solution, so I wrote a second solution that's more robust. It also demonstrates monadic style. The new solution is at the bottom. Dean On Thu, 23 Jan 2003, Dean Herington wrote:
On Sun, 19 Jan 2003, Nick Name wrote:
I got another trouble: I need to build a record type like
Package { name :: String, version :: Int , mantainer :: String ... other fields ... }
from a list of string of the form
["Package: ..." , "Mantainer: ..." , "Version: ..." , ... ]
where the fields are not bound to be in a particular order, except for Package wich is always the first of a record.
The natural solution in this case seems to be a mutable record, and an iteration over the list. Has someone got ideas? This appear to be a particularly difficult problem in haskell and it should not be.
V.
Here's one way to do it:
module ReadRecord where
import Maybe (isJust)
data Package = Package { name :: Maybe String, version :: Maybe Int, maintainer :: Maybe String } deriving Show
parsePackage :: [String] -> Package parsePackage = foldl (parseItem trials) (Package Nothing Nothing Nothing) where parseItem (f:fs) p s = maybe (parseItem fs p s) id (f p s) parseItem [] _ s = error $ "can't match " ++ show s
trials = [ try "Package" (ij.name) (\ p v -> p{name = Just v}), try "Version" (ij.version) (\ p v -> p{version = Just $ read v}), try "Maintainer" (ij.maintainer) (\ p v -> p{maintainer = Just v}) ]
try key tester setter pkg str = fmap parse $ match (key ++ ": ") str where parse text = if tester pkg then error $ "duplicate field: " ++ key else setter pkg text
match want str = if want == pre then Just post else Nothing where (pre, post) = splitAt (length want) str
ij = isJust
main = mapM_ try goods try = print . parsePackage
goods = [ [], ["Package: p1", "Version: 1", "Maintainer: m1"], ["Maintainer: m2", "Package: p2"] ]
bad1 = ["Version: v-b1", "Foo: foo-b1"] bad2 = ["Maintainer: me", "Maintainer: me"] bad3 = ["Version: foo"]
-- Dean
module ReadRecord where import Maybe (isJust) import Monad import Control.Monad import Control.Monad.Error data Package = Package { name :: Maybe String, version :: Maybe Int, maintainer :: Maybe String } deriving Show parsePackage :: [String] -> Either String Package parsePackage = foldM parseItem (Package Nothing Nothing Nothing) where parseItem p s = join $ msum [ trial p s | trial <- trials ] trials = [ try "Package" (isJust . name) (\ p t -> return p{name = Just t}), try "Version" (isJust . version) (\ p t -> do v <- int t; return p{version = Just v}), try "Maintainer" (isJust . maintainer) (\ p t -> return p{maintainer = Just t}), \ _ str -> return $ fail $ "can't match " ++ show str ] try fld full set p s = match (fld ++ ": ") s >>= return . parse where parse t = if full p then fail $ "duplicate field: " ++ fld else set p t match want str = do guard (want == pre); return post where (pre, post) = splitAt (length want) str int text = case reads text of [(val,"")] -> return val _ -> fail $ "invalid Int: " ++ text main = mapM_ try trials try = print . parsePackage trials = goods ++ bads goods = [ [], ["Package: p1", "Version: 1", "Maintainer: m1"], ["Maintainer: m2", "Package: p2"]] bads = [bad1, bad2, bad3] bad1 = ["Package: b1", "Foo: foo-b1"] bad2 = ["Maintainer: me1", "Maintainer: me2"] bad3 = ["Version: foo"]
Nick Name wrote:
I would like to use hGetContents just to retrieve the list of the lines of a file, but if I code a function like:
linesFromFile :: FilePath -> IO [String] linesFromFile f = do h <- openFile f ReadMode l <- hGetContents h hClose h return (lines l)
I obviously always get the empty list as a result. How should I code the function?
Just omit the hClose; hGetContents will automatically close the handle once all of the data has actually been read. See §11.2.1 of the library report for details. -- Glynn Clements <glynn.clements@virgin.net>
On Sun, 19 Jan 2003 17:19:52 +0000 Glynn Clements <glynn.clements@virgin.net> wrote:
Just omit the hClose; hGetContents will automatically close the handle once all of the data has actually been read. See §11.2.1 of the library report for details.
Thanks for this pointer. Quoting from the report: A semi-closed handle becomes closed: * if hClose is applied to it; * if an I/O error occurs when reading an item from the file item from the stream; * or once the entire contents of the file has been read. What happens if one does NOT read the whole contents, but there are no more references to the results of hGetContents? Is the file handle closed anyway ? Here's an example of what I mean: openFile n ReadMode >>= hGetContents >>= return . (take 10) Vincenzo -- First they ignore you, then they laugh at you, then they fight you, then you win. [Gandhi]
participants (4)
-
Dean Herington -
Glynn Clements -
Mark P Jones -
Nick Name