我正在尝试接受用户输入并以元组列表的形式转换它。
我想要做的是,我需要从用户那里获取数据并以形式转换它
[(Code,Name, Price)]
并最终将此用户输入与前一个列表组合在一起,并将新列表写入同一文件。
我面临的问题是,一旦程序完成用户输入,WinHugs就会显示错误,如Program error: Prelude.read: no parse
。
以下是代码:
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
答案 0 :(得分:0)
问题是,当您同时写入文件时,您正在使用惰性IO来读取文件。当read
看到已部分写入的数据时,这会导致问题。
在尝试写入文件之前,我们需要强制读取输入数据。一种方法是使用seq
强制将产品列表读入内存。
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
此外,如果文件为空,则会失败。在第一次运行代码之前,该文件应至少包含[]
,以便它将作为空列表进行解析。
答案 1 :(得分:0)
代码看起来很好,除了某些样式点。它应该像那样工作。尝试更多地分开关注点。 “无解析”异常意味着read
函数无法将其参数字符串转换为所需类型。 Hugs附带的基础库可能对空格和换行更具限制性。我建议一般使用GHC而不是Hugs。
如果您感兴趣:您可能需要考虑的一个样式点是使用withFile
而不是openFile
/ hClose
组合。您可能还想将writeFile
与show
:
writeFile "testx.txt" (show w)
另一个样式点:您的input_taker
操作不应返回列表。没有理由返回列表。返回单个元组,因此您可以使用(:)
代替(++)
。一般来说,(++)
的使用表明您可能采取了错误的方法。
此外,您的ProductDatabase
类型名称具有误导性,因为我会将[ProductDatabase]
解释为数据库列表。你的元组是Product
。
最终的风格点:这真的只是代码美,所以它是有争议的。这不是C / C ++,所以你真的想写f x
而不是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)