Преобразование строки в целое число / Float в Haskell?
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's .
Я получаю следующую ошибку, которая, я думаю, потому что 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, соответственно?
4 ответов:
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) = ...здесь
:является (правоассоциативным) двоичным оператором, который добавляет элемент в список. RHS элемента должен быть списком. Поэтому, учитывая выражениеa:b:c, Haskell выведет следующие типы:a :: String b :: String c :: [String]т. е.
cбудет рассматриваться как список строк. Очевидно, что это не может бытьreadили перешло в любые функции, ожидающие строку.вместо этого вы должны использовать
createGroceryItem [a, b, c] = ...если в списке должно быть ровно 3 пункта, или
createGroceryItem (a:b:c:xs) = ...если ≥3 детали приемлемы.
также (2), выражение
makeGroceryItem a read b read cбудет интерпретироваться как
makeGroceryItemпринимает 5 аргументов, 2 из которых являются
хотя этот вопрос уже есть ответ, я настоятельно рекомендую использовать
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возвращает пустой список.это легко шаблон-матч на успех и неудачу, и он не будет взрывай себе в лицо!
две вещи:
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 параметра.
filterNumberFromString :: String -> String filterNumberFromString s = let allowedString = ['0'..'9'] ++ ['.', ','] toPoint n | n == ',' = '.' | otherwise = n f = filter (`elem` allowedString) s d = map toPoint f in d convertStringToFloat :: String -> Float convertStringToFloat s = let betterString = filterNumberFromString s asFloat = read betterString :: Float in asFloat print (convertStringToFloat "15,00" + 1)-> печать 16.0
вот как я решил эту задачу в моем проекте.
Comments