problems with trivial number conversions in Haskell

旧街凉风 提交于 2019-12-11 11:52:51

问题


I am attempting to write a trivial function to drop the last digit of a number and return the rest of the number.

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

however, when I try to load this into ghci, I get:

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

However, running this code in ghci:

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

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

My question is, what am I doing wrong? And why is (the identical code?) working in ghci?


回答1:


It's not identical. You can check this easily:

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

The problem is that both 10 and 101 have type Num a => a, regardless of where you use them. So logBase 10 101 used them with the default Fractional instance (Double), whereas quot used them with the default Integral instance.

That being said, your function doesn't "drop" the last digit. If you just want to transform 12345 to 1234, you can simplify dropLastDigit to

dropLastDigit x = x `div` 10

If you, however, want to transform 12345 to 12340, you just have to multiply by ten afterwards:

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



回答2:


Change your function to

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

The code you're running in GHCi is not identical. You've replaced x by 101. The x in your function was annotated (by type signature) to be of type b for any type b in the Integral class, but logBase needs something in the Floating class.

On the other hand, the literal 101 is of type Num a => a, i.e., it is overloaded and can be used at any numeric type. So GHCi can use it at type Integer on the first occurrence, as an argument of quot, and as a Double on the second occurrence, as an argument to logBase.



来源:https://stackoverflow.com/questions/33619011/problems-with-trivial-number-conversions-in-haskell

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!