#haskell
#haskell
Вопрос:
Я пытаюсь использовать пользовательский ввод и преобразовать его в виде списка кортежей. Что я хочу сделать, так это то, что мне нужно взять данные от пользователя и преобразовать их в форму [(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
Ответ №1:
Проблема в том, что вы используете ленивый ввод-вывод для чтения из файла во время одновременной записи в него. Это вызывает проблемы при 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. : Я получаю сообщение об ошибке «Не удается найти импортированный модуль». DeepSeq»»
2. @Roy: Это в пакете deepseq. Я не слишком знаком с тем, как устанавливать пакеты на WinHugs, но я бы рекомендовал вместо этого установить платформу Haskell , поскольку она намного более современная и включает в себя ряд распространенных пакетов, включая deepseq, из коробки.
3. Любой другой способ сделать это, я имею в виду, кроме deepseq
4. @Roy: На самом деле, поскольку
read
будет принудительно вводить весь ввод, этого должно быть достаточно для использованияseq
вместоdeepseq
. Попробуйте это.5. : Пробовал. Но та же ошибка «Ошибка программы: Prelude.read: нет синтаксического анализа»
Ответ №2:
Для меня код выглядит нормально, за исключением определенных точек стиля. Это должно работать так. Постарайтесь больше разделять проблемы. Исключение «нет синтаксического анализа» означает, что read
функция не смогла преобразовать строку своего аргумента в нужный тип. Базовая библиотека, поставляемая с Hugs, может быть более строгой в отношении пробелов и перевода строк. Я бы рекомендовал использовать GHC вместо Hugs в целом.
В случае, если вам интересно: один пункт стиля, который вы, возможно, захотите рассмотреть, — это использование withFile
вместо комбинации openFile
/ hClose
. Вы также можете использовать writeFile
с show
:
writeFile "testx.txt" (show w)
Еще один момент стиля: ваше input_taker
действие не должно возвращать список. На самом деле нет причин возвращать список. Вместо этого верните один кортеж, чтобы вы могли использовать (:)
вместо ( )
. В целом использование ( )
указывает на то, что вы, возможно, используете неправильный подход.
Кроме того, ваше ProductDatabase
имя типа вводит в заблуждение, потому что я бы интерпретировал [ProductDatabase]
его как список баз данных. Ваш кортеж — a 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)