【问题标题】:Haskell cast Integer to IntHaskell 将 Integer 转换为 Int
【发布时间】:2018-10-04 10:34:28
【问题描述】:

为什么第一个是正确的而第二个不是? 我想以第二种方式实现代码,这样我就不必每次都调用fromInteger,但我不明白如何......

正确

bits :: Integer -> Int 
bits 0 = 0
bits n = fromInteger n `mod` 2 + bits(fromInteger n `div` 2) 

不正确

bits :: Integer -> Int 
bits 0 = 0
bits n = let m = fromInteger n in m `mod` 2 + bits(m `div` 2) 

【问题讨论】:

  • 安全版本实际上是bits n = fromInteger (n`mod`2) + bits (n`div`2)。或者case n`divMod`2 of (q,r) -> fromInteger r + bits q.
  • 调用bits 比简单调用fromInteger 更好吗?除了使用更多的 CPU 周期之外,bits fromInteger。您基本上是通过识别12 == 8 + 412 :: Integer 转换为12 :: Int,然后添加84 以返回12

标签: haskell casting integer


【解决方案1】:

因为第二次通话不需要它:

bits :: Integer -> Int 
bits 0 = 0
bits n = fromInteger n `mod` 2 + bits (n `div` 2) 

第二个fromInteger 只是再次导致Integer,由参数强制为bits

【讨论】:

    【解决方案2】:

    这是此版本不进行类型检查的原因:

    bits :: Integer -> Int
    bits 0 = 0
    bits n = let m = fromInteger n in m `mod` 2 + bits(m `div` 2)
    

    首先,请注意m 的第一次用法要求mInt,因为bits 调用的结果必须是Int,这意味着加法的左侧(即m `mod` 2) 必须是 Int。为什么是这样?嗯,这是因为+ 运算符的签名是:

    (+) :: (Num a) => a -> a -> a
    

    这要求+ 的两个参数与其结果具有相同的类型。同样,因为m `mod` 2 必须是Int,所以`mod` 调用的左侧(即m)必须是Int,因为mod 有签名:

    mod :: (Integral a) => a -> a -> a
    

    所以,这就是m 的第一次使用需要m :: Int 的原因。呼!

    出于同样的原因,m第二个用法要求mInteger。这是因为表达式bits (m `div` 2)bits 的参数必须是Integer,这要求`div` 运算符的左侧必须是Integer

    因此,我们要求 m 既是 Int 又是 Integer。这不一定是个问题。如果你改为写:

    bits :: Integer -> Int
    bits 0 = 0
    bits n = m `mod` 2 + bits(m `div` 2)
      where m :: (Integral a) => a
            m = fromInteger n
    

    并且给m一个显式的多态类型签名,那么m可以同时用作IntInteger。然而,由于所谓的单态限制,没有明确的类型签名,m 需要有一个非多态(即单态类型)。如果添加编译指示:

    {-# LANGUAGE NoMonomorphismRestriction #-}
    

    到文件的顶部,然后原始定义类型检查正常:

    {-# LANGUAGE NoMonomorphismRestriction #-}
    
    bits :: Integer -> Int
    bits 0 = 0
    bits n = let m = fromInteger n in m `mod` 2 + bits(m `div` 2)
    

    不过,其他人已经注意到,您实际上在这两个地方都不需要fromInteger;并且同时使用IntInteger 是不必要的,并且使用带有约束的单个整数类型(Integral a可能会更好。

    此外,如果您希望将此功能用于实际工作而不是练习,它已经在模块Data.Bits 中以popCount 的形式提供。

    【讨论】:

      【解决方案3】:

      您也许可以稍微调整一下签名并删除所有fromIntegers。

      bits :: Integral a => a -> a 
      bits 0 = 0
      bits n = n `mod` 2 + bits (n `div` 2)
      

      【讨论】:

      • 但原来的签名实际上是有道理的,因为这个函数可以将大量的数字分解成一个小的摘要。
      猜你喜欢
      • 1970-01-01
      • 2016-12-26
      • 1970-01-01
      • 2011-02-16
      • 2012-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-29
      相关资源
      最近更新 更多