wardz
wardz

Reputation: 379

Integral type class comparisons

Currently brushing up on my Haskell by doing Codewars. I have made the following code,

import Data.Char(digitToInt)

calc :: String -> Int
calc s = sum $ map (\i -> (digitToInt i)^n) s
        where n = length s

narcissistic :: Integral n => n -> Bool
narcissistic n = calc s == n
                where s = show n

Which produces,

Couldn't match expected type 'Int' with actual type 'n'
      'n' is a rigid type variable bound by
        the type signature for:
          narcissistic :: forall n. Integral n => n -> Bool

To my knowledge this is caused by the fact that the narcissistic function taking an input n which is within the Integral type class (Int or Integer). However the calc function produces an Int. Thus I cannot compare the result of calc and the n.

My question is thus, what would be the ideal way to work with these type classes, and how would I be able to implement a function such as calc which would possibly work with the Integral class type (unable to do so because of the digitToInt?).

Upvotes: 3

Views: 88

Answers (2)

Bergi
Bergi

Reputation: 665020

How would I be able to implement a function such as calc which would possibly work with the Integral class type (unable to do so because of the digitToInt?).

You can use fromIntegral to convert that Int to any Integral (or even more generically, any Num, but we don't need that here):

calc :: Integral i => String -> i
calc s = sum $ map (\i -> (fromIntegral $ digitToInt i)^n) s
        where n = length s

Upvotes: 0

chepner
chepner

Reputation: 531878

calc specifically returns an Int, which means == also expects an Int, but you are only providing an Integral n => n value. Sure, narcissistic could be called with an Int, but it could just as well be called with an Integer or some other type with an Integral instance.

To make the comparison, you need a common type. You can use toInteger :: Integral a => a -> Integer on both calc s and n to get Integer values that can be compared directly.

narcissistic :: (Show n, Integral n) => n -> Bool
narcissistic n = toInteger (calc s) == toInteger n
     where s = show n

Note that Integral does not imply Show; you need to add that to the constraints as well.

However... you can't know that the number calc computes from the String input will fit in an Int; you should return an Integer in the first place, then use fromIntegral :: (Integral a, Num b) => a -> b to turn n into an Integer.

calc :: String -> Integer
calc s = sum $ map (\i -> (fromIntegral (digitToInt i))^n) s
        where n = length s

narcissistic :: Integral n => n -> Bool
narcissistic n = calc s == fromIntegral n
                where s = show n

Upvotes: 6

Related Questions