Преобразование строки в целое число / 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, соответственно?

800   4  

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

    Ничего не найдено.