Reputation: 379
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
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 thedigitToInt
?).
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
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