How to combine user input with list of tuples and write the complete list of tuples to the file?
I am trying to take user input and convert it in the form of a list of tuples.
What I want to do is that, I need to take the data from the user and convert it in the form of
[(Code,Name, Price)]
and finally combine this user input with the previous list and write the new list to the same file.
The problem I am facing is that as soon as the program completes taking 开发者_高级运维user input, WinHugs is showing an error like this Program error: Prelude.read: no parse
.
Here is the code:
type Code=Int
type Price=Int
type Name=String
type ProductDatabase=(Code,Name,Price)
finaliser=do
a<-input_taker
b<-list_returner
let w=a++b
outh <- openFile "testx.txt" WriteMode
Print outh w
Close outh
The problem is that you're using lazy IO to read from a file while you're writing to it at the same time. This causes problems when read
sees data that has been partially written.
We need to force the reading of the input data to be complete before you try writing to the file. One way of doing this is to use seq
to force the list of products to be read into memory.
list_returner :: IO ([ProductDatabase])
list_returner = do
inh <- openFile "testx.txt" ReadMode
product_text <- hGetContents inh
let product :: [ProductDatabase]
product = read product_text
product `seq` hClose inh
return product
Also, this will fail if the file is empty. The file should contain at least []
before running your code the first time, so that it will parse as the empty list.
The code looks fine to me, except for certain style points. It should work like that. Try to separate concerns more. The exception "no parse" means that the read
function was unable to convert its argument string to the desired type. The base library coming with Hugs may be more restrictive on spaces and line feeds. I would recommend using GHC instead of Hugs in general.
In case you're interested: One style point you may want to consider is using withFile
instead of an openFile
/hClose
combination. You may also want to use the writeFile
with show
:
writeFile "testx.txt" (show w)
Another style point: Your input_taker
action should not return a list. There is really no reason to return a list. Return a single tuple instead, so you can use (:)
instead of (++)
. In general the usage of (++)
indicates that you may be taking the wrong approach.
Further your ProductDatabase
type name is misleading, because I would interpret [ProductDatabase]
as a list of databases. Your tuple is a Product
.
Final style point: This is really just about code beauty, so it's controversial. This is not C/C++, so you would really want to write f x
instead of f(x)
:
...
return product
-- Since your `Product` is just a type alias, I would use
-- a smart constructor:
product :: Code -> Name -> Price -> Product
product = (,,)
readProduct :: IO Product
readProduct = do
...
code <- fmap read getLine
...
name <- getLine
...
price <- fmap read getLine
return (product code name price)
精彩评论