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

Posted

技术标签:

【中文标题】在 Haskell 中将字符串转换为整数/浮点数?【英文标题】:Convert String to Integer/Float in Haskell? 【发布时间】:2011-01-28 22:21:39 【问题描述】:
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 接受 FloatInt

*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*

但是我如何分别制作FloatInt 类型的bc

【问题讨论】:

你有一个有趣的项目。它是干什么用的? 【参考方案1】:

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 个是 read 函数。您需要使用括号:

makeGroceryItem a (read b) (read c)

【讨论】:

@KennyTM: read "123.456" :: Float 。这个语法是什么意思? :: 这里是什么? read 是函数吗? @Nawaz:是的,read 是一个函数。 f :: T 表达式强制 f 具有类型 T @KennyTM:所以read "123.456" ::Float 的语法大致相当于C 中的sscanf("123.456", "%f", &fnum);,对吧? @Nawaz:仅适用于read 函数。详情请见***.com/questions/5926826/…。 Read 在内部实际上是如何工作的?它是否将字符串分解为 Char 列表。那么它是否有一个从char到int的字典,并将char列表与字典进行比较以获得对应的int?【参考方案2】:

两件事:

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 个参数的函数时,编译器会报错。

【讨论】:

【参考方案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 返回一个空列表。

成功和失败的模式匹配很容易,而且不会在你的脸上炸毁!

【讨论】:

好建议!从读取返回的列表中提取结果项目的首选方法是什么?两个fst 电话? 从base-4.6开始,Text.Read中有readMaybe :: Read a => String -> Maybe a,比本例使用reads方便。【参考方案4】:
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

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

【讨论】:

【参考方案5】:

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

Prelude> import Text.Read
Prelude Text.Read> readMaybe ("1.5") :: Maybe Float
Just 1.5

【讨论】:

以上是关于在 Haskell 中将字符串转换为整数/浮点数?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Java 中将整数转换为浮点数?

如何在 C++ 中将数字转换为字符串,反之亦然

如何在python中将23位浮点数从字符串转换为浮点数并返回?

在 C# 中将字符串转换为浮点数

在 C++ 中将字符串转换为浮点数

无法在python中将字符串转换为浮点数