在Haskell中将字符串转换为整数/浮点?

在Haskell中将字符串转换为整数/浮点?,haskell,floating-point,int,Haskell,Floating Point,Int,输入的格式为[“Apple”,“15.00”,“5”],我使用Haskell的words函数将其分解 我得到以下错误,我认为是因为makeGroceryItem接受Float和Int data GroceryItem = CartItem ItemName Price Quantity | StockItem ItemName Price Quantity makeGroceryItem :: String -> Float -> Int -> GroceryItem mak

输入的格式为
[“Apple”,“15.00”,“5”]
,我使用Haskell的
words
函数将其分解

我得到以下错误,我认为是因为
makeGroceryItem
接受
Float
Int

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

但是如何分别使
b
c
类型为
Float
Int

read
可以将字符串解析为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*
但问题(1)在于你的模式:

Prelude> :set +t
Prelude> read "123.456" :: Float
123.456
it :: Float
Prelude> read "123456" :: Int
123456
it :: Int
这里的
是一个(右关联)二进制运算符,它将一个元素前置到列表中。元素的RHS必须是列表。因此,给定表达式
a:b:c
,Haskell将推断以下类型:

createGroceryItem (a:b:c) = ...
i、 e.
c
将被视为字符串列表。显然,它不能被
读取
或传递到任何需要字符串的函数中

相反,你应该使用

a :: String
b :: String
c :: [String]
如果列表必须正好有3项,或

createGroceryItem [a, b, c] = ...
如果≥3项是可以接受的

还有(2),表达式

createGroceryItem (a:b:c:xs) = ...
将被解释为带有5个参数的
makeGroceryItem
,其中2个是
read
函数。您需要使用括号:

makeGroceryItem a read b read c
两件事:

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
因为
+
不同


同时,在右边——给出错误信息的那一边——你必须用括号将表达式分组。否则,
parse
将被解释为要传递给
makeGroceryItem
的值,因此当您尝试将5个参数传递给只接受3个参数的函数时,编译器会发出抱怨。

即使这个问题已经有了答案,我强烈建议使用
reads
进行字符串转换,因为它更安全,因为它不会因为无法恢复的异常而失败

createGroceryItem (a : b : c : _) = makeGroceryItem a (parse b) (parse c)
-- pattern match error if fewer than 3 items in list, ignore excess items
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)
成功时,
读取
返回一个只包含一个元素的列表:一个元组,由转换后的值和可能无法转换的额外字符组成。失败时,
读取
返回空列表

成功与失败的模式匹配很容易,而且不会在你面前爆炸

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)]
[]
->打印16.0


这就是我在项目中解决此任务的方法。

readMaybe
可以用于此。它也是一个total函数,而不是
read
(可能引发异常)


@肯尼特:
读“123.456”::浮点
。这个语法是什么意思?什么是
read
是函数吗?@Nawaz:Yes
read
是函数。
f::T
表达式强制
f
具有类型
T
@KennyTM:因此语法
为“123.456”::Float
大致相当于
sscanf(“123.456”、%f”、&fnum)在C中,对吗?@Nawaz:仅用于
read
功能。有关详细信息,请参阅。阅读实际上是如何工作的?它是否将字符串分解为字符列表。那么它是否有一个从char到int的字典,并将char列表与字典进行比较,以获得相应的int?这是一个很好的建议!从读取返回的列表中提取结果项的首选方法是什么?两个
fst
调用?自base-4.6以来,在
文本中有一个。Read
,这比在本例中使用
reads
更方便。您有一个有趣的项目。这是干什么用的?
Prelude> import Text.Read
Prelude Text.Read> readMaybe ("1.5") :: Maybe Float
Just 1.5