gpt4 book ai didi

haskell - 将 String 转换为 Int 检查是否溢出

转载 作者:行者123 更新时间:2023-12-02 10:11:19 26 4
gpt4 key购买 nike

当我尝试将一个非常长的整数转换为 Int 时,我很惊讶没有抛出任何错误:

Prelude> read "123456789012345678901234567890" :: Int
-4362896299872285998
Text.Read 模块中的

readMaybe 给出相同的结果。

两个问题:

  • 我应该调用哪个函数来执行安全转换?
  • 地球上类型最安全的语言怎么会允许如此不安全的事情发生?

更新1:

这是我尝试编写一个检查边界的 read 版本:

{-# LANGUAGE ScopedTypeVariables #-}

parseIntegral :: forall a . (Integral a, Bounded a) => String -> Maybe a
parseIntegral s = integerToIntegral (read s :: Integer) where
integerToIntegral n | n < fromIntegral (minBound :: a) = Nothing
integerToIntegral n | n > fromIntegral (maxBound :: a) = Nothing
integerToIntegral n = Just $ fromInteger n

这是我能做的最好的事情吗?

最佳答案

背景:为什么未经检查的溢出实际上很棒

Haskell 98 明确未指定溢出行为,这对实现者有利,但对其他人不利。 Haskell 2010 在两个部分中讨论它 - 在从 Haskell 98 继承的部分中,它没有明确指定,而在 Data.Int 的部分中。和Data.Word ,已指定。这种不一致有望最终得到解决。

GHC 很友善地明确指定了它:

All arithmetic is performed modulo 2^n, where n is the number of bits in the type.

这是一个非常有用的规范。特别是,它保证 Int , Word , Int64 , Word32等,形成环,甚至principal ideal rings ,在加法和乘法下。这意味着算术将始终正确运行 - 您可以以多种不同的方式转换表达式和方程,而不会破坏事物。在溢出时引发异常会破坏所有这些属性,从而使程序的编写和推理变得更加困难。唯一真正需要小心的是当您使用类似 < 之类的比较运算符时和compare - 固定宽度整数不形成有序组,因此这些运算符有点敏感。

为什么不检查读取是有意义的

读取整数涉及许多乘法和加法。它还需要很快。检查以确保读取内容“有效”并不那么容易快速完成。特别是,虽然很容易找出加法是否溢出,但找出乘法是否溢出却不容易。我能想到的唯一明智的方法是对 Int 执行检查读取是

  1. 读作 Integer ,检查,然后转换。 Integer算术比 Int 昂贵得多算术。对于较小的东西,例如 Int16 ,可以通过 Int 来完成读取,检查Int16溢出,然后缩小。这更便宜,但仍然不是免费的。

  2. 将十进制数与 maxBound 进行比较(或者,对于负数, minBound )在阅读时。这似乎更有可能相当有效,但仍然会产生一些成本。正如本答案的第一部分所解释的,溢出并没有本质上的错误,因此尚不清楚抛出错误实际上比给出模 2^n 的答案更好。

关于haskell - 将 String 转换为 Int 检查是否溢出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29587201/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com