Haskell 中的简单数字转换问题

problems with trivial number conversions in Haskell

我正在尝试编写一个简单的函数来删除数字的最后一位和 return 数字的其余部分。

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 中工作?

将函数更改为

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

您在 GHCi 中 运行 的代码不相同。您已将 x 替换为 101。对于 Integral class 中的任何类型 b,函数中的 x 被注释(通过类型签名)为 b 类型,但是 logBase Floating class.

中需要一些东西

另一方面,字面值 101Num a => a 类型,也就是说,它被重载并且可以用于任何数字类型。因此 GHCi 可以在第一次出现时以类型 Integer 使用它,作为 quot 的参数,并在第二次出现时作为 Double 作为 logBase 的参数。

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

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 实例一起使用。

也就是说,您的函数没有 "drop" 最后一位。如果只想将12345转化为1234,可以将dropLastDigit简化为

dropLastDigit x = x `div` 10

但是,如果您想要将 12345 转换为 12340,则只需乘以 10:

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