Haskell中琐碎数字转换的问题

时间:2015-11-09 21:56:44

标签: haskell numbers type-conversion ghci

我正在尝试编写一个简单的函数来删除数字的最后一位数字并返回其余数字。

dropLastDigit :: (Integral b) => b -> b
dropLastDigit x = (quot x 10) * (floor $ logBase 10 x)

但是,当我尝试将其加载到ghci时,我得到:

Could not deduce (Floating b) arising from a use of ‘logBase’
    from the context (Integral b)
      bound by the type signature for
                 dropLastDigit :: Integral b => b -> b
      at haskelljokes.hs:6:18-39
    Possible fix:
      add (Floating b) to the context of
        the type signature for dropLastDigit :: Integral b => b -> b
    In the second argument of ‘($)’, namely ‘logBase 10 x’
    In the expression: floor $ logBase 10 x
    In an equation for ‘dropLastDigit’:
        dropLastDigit x = floor $ logBase 10 x

但是,在ghci中运行此代码:

:t (quot 101 10) * (floor $ logBase 10 101)

生成:(quot 101 10) * (floor $ logBase 10 101) :: Integral a => a

我的问题是,我做错了什么?为什么(相同的代码?)在ghci中工作?

2 个答案:

答案 0 :(得分:4)

将您的功能更改为

dropLastDigit :: (Integral b) => b -> b
dropLastDigit x = (quot x 10) * (floor $ logBase 10 (fromIntegral x))

您在GHCi中运行的代码并不完全相同。您已x替换101。对于x类中的任何类型b,函数中的b已注释(按类型签名)为Integral类型,但logBase需要某些内容在Floating班。

另一方面,文字101的类型为Num a => a,即它已重载并且可以在任何数字类型中使用。因此,GHCi可以在第一次出现时在类型Integer上使用它,作为quot的参数,在第二次出现时作为Double使用它作为logBase的参数。

答案 1 :(得分:3)

这不完全相同。您可以轻松查看:

ghci> let value101 = 101 :: Integral b => b
ghci> let value10  = 10  :: Integral b => b
ghci> (quot value101 value10) * (floor $ logBase value10 value101)

<interactive>:7:28:
    Could not deduce (RealFrac s0) arising from a use of `floor'
    from the context (Integral a)
      bound by the inferred type of it :: Integral a => a
      at <interactive>:7:1-60
    The type variable `s0' is ambiguous
    Note: there are several potential instances:
      instance RealFrac Double -- Defined in `GHC.Float'
      instance RealFrac Float -- Defined in `GHC.Float'
      instance Integral a => RealFrac (GHC.Real.Ratio a)
        -- Defined in `GHC.Real'
    In the expression: floor
    In the second argument of `(*)', namely
      `(floor $ logBase value10 value101)'
    In the expression:
      (quot value101 value10) * (floor $ logBase value10 value101)

-- even more...

问题在于10101都有Num a => a类型,无论您在何处使用它们。因此logBase 10 101将它们与默认的Fractional实例(Double)一起使用,而quot将它们与默认的Integral实例一起使用。

话虽如此,你的功能并没有“丢弃”最后一位数字。如果您只想将12345转换为1234,则可以将dropLastDigit简化为

dropLastDigit x = x `div` 10

但是,如果您想将12345转换为12340,则必须在之后乘以10:

dropLastDigit x = 10 * (x `div` 10)