data GroceryItem = CartItem ItemName Price Quantity | StockItem ItemName Price Quantity
makeGroceryItem :: String -> Float -> Int -> GroceryItem
makeGroceryItem name price quantity = CartItem name price quantity
I want to create a `GroceryItem` when using a `String` or `[String]`
createGroceryItem :: [String] -> GroceryItem
createGroceryItem (a:b:c) = makeGroceryItem a b c
Вход будет в формате ["Apple","15.00","5"]
который я разбил использование Haskell words
функция.
Я получаю следующую ошибку, которая я думаю, то, потому что makeGroceryItem
принимает a Float
и Int
.
*Type error in application
*** Expression : makeGroceryItem a read b read c
*** Term : makeGroceryItem
*** Type : String -> Float -> Int -> GroceryItem
*** Does not match : a -> b -> c -> d -> e -> f*
Но как я делаю b
и c
из типа Float
и Int
, соответственно?
read
может разобрать строку на float и int:
Prelude> :set +t
Prelude> read "123.456" :: Float
123.456
it :: Float
Prelude> read "123456" :: Int
123456
it :: Int
Но проблема (1) в вашем шаблоне:
createGroceryItem (a:b:c) = ...
Здесь :
- (правоассоциативный) бинарный оператор который добавляет элемент к списку. Правая часть элемента должна быть списком. Следовательно, учитывая выражение a: b: c
, Haskell выведет следующие типы:
a :: String
b :: String
c :: [String]
т.е. c
будет рассматриваться как список строк. Очевидно, его нельзя прочитать
или передать каким-либо функциям, ожидающим String.
Вместо этого следует использовать
createGroceryItem [a, b, c] = ...
, если в списке должно быть ровно 3 элемента, или
createGroceryItem (a:b:c:xs) = ...
, если допускается ≥3 элементов.
Также (2) выражение
makeGroceryItem a read b read c
будет интерпретироваться как makeGroceryItem
с 5 аргументами, 2 из которых являются функцией read
. Вам нужно использовать круглые скобки:
makeGroceryItem a (read b) (read c)
Две вещи:
createGroceryItem [a, b, c] = makeGroceryItem a (parse b) (parse c)
-- pattern match error if not exactly 3 items in list
или, альтернативно,
createGroceryItem (a : b : c : _) = makeGroceryItem a (parse b) (parse c)
-- pattern match error if fewer than 3 items in list, ignore excess items
, потому что :
не то же самое, что ++
.
Между тем, на правой стороне - стороне, которая выдает сообщение об ошибке, которое вы видите - вы должны группировать выражения, используя квадратные скобки. В противном случае parse
интерпретируется как значение, которое вы хотите передать в makeGroceryItem
, поэтому компилятор жалуется, когда вы пытаетесь передать 5 аргументов функции, которая принимает только 3 параметра.
Несмотря на то, что на этот вопрос уже есть ответ, я настоятельно рекомендую использовать reads
для преобразования строк, потому что это намного безопаснее, так как он не терпит неудачу с невосстановимым исключением.
reads :: (Read a) => String -> [(a, String)]
Prelude> reads "5" :: [(Double, String)]
[(5.0,"")]
Prelude> reads "5ds" :: [(Double, String)]
[(5.0,"ds")]
Prelude> reads "dffd" :: [(Double, String)]
[]
Об успехе, reads
возвращает список с ровно одним элементом: кортеж, состоящий из преобразованного значения и, возможно, неконвертируемых дополнительных символов. При сбое reads
возвращает пустой список.
Легко сочетать успехи и неудачи, и это не взорвется вам в лицо!