tags:

views:

264

answers:

3

I am learning Haskell. I have created function which returns multiplication table up to 'n' in base 'b'. Numbers are padded to 'w' digits. As the last step, I want to compute 'w' automatically. Why does this not compile?

-- Number of digits needed for the multiplication table n*n in base 'base'
nOfDg :: Int -> Int-> Int 
nOfDg n base = 1 + floor ( logBase base (n*n)) 

error:

No instance for (Floating Int)
     arising from a use of `logBase' at C:\haskel\dgnum.hs:4:24-38
   Possible fix: add an instance declaration for (Floating Int)
   In the first argument of `floor', namely `(logBase b (n * n))'
   In the second argument of `(+)', namely `floor (logBase b (n * n))'
   In the expression: 1 + floor (logBase b (n * n))
+4  A: 

logBase takes two parameters which implement the floating typeclass. You'll need to call fromIntegral on the parameters before passing them to logBase. This compiled for me with 6.10.3:

nOfDg :: Int -> Int-> Int
nOfDg n base = 1 + floor ( logBase (fromIntegral base) (fromIntegral (n*n)))

You have to remember that Haskell is very strongly typed, so you can't just assume that the Int parameters supplied to your function will automatically be coerced to the floating numbers that log functions generally take.

Andy
+3  A: 

logBase is declared to work on floating point types. Int is not a floating point type and there is no automatic conversion in Haskell. Try this:

-- Number of digits needed for the multiplication table n*n in base 'base'
nOfDg :: Int -> Float -> Int
nOfDg n base = 1 + floor (logBase base (fromIntegral (n*n)))
Dan Dyer
I guess you'll need `(fromIntegral base)` as well.
Jason Orendorff
@Jason: Not with the type Dan gave that function, you won't.
Chuck
Yeah, depends on how you want to use it. Either do it like I have it if it's OK to change the type signature, or use Andy's version if not.
Dan Dyer
+1  A: 

From the Prelude :

logBase :: Floating a => a -> a -> a

It means that using logBase you must be using a floating type. But Int is not a floating Type, and there is no automatic conversion for numeric types, so you have to convert it from Int to a Floating type :

nOfDg n base = 1 + floor ( logBase (toEnum base) (toEnum n))

the toEnum function take an int as parameter and return an "Enum" type. The good part is that Float is an instance of Enum, so you could use it

toEnum :: Enum a => Int -> a

You should read/document you about standard type classes in haskell for numeric types (Num,Fractional,Integral, Floating...) as they often pop-up in code, learning conversions could be useful.

Edit : this Haskell Wiki Book provide a very useful graphic of relationship between standards type class, including numeric types.

Raoul Supercopter