3
votes

I'm new to Haskell and I'm trying to get the length of a number in base 10 so I created length' function:

length' :: (Integral a) => a -> a
length' a = length $ show a

But Haskell gives me "Couldn't match type" error because length returns Int. I don't get why it gives me an error since Int an instance of Integral...

2
Because your output is Int and here you make a claim that the type can be any Integral type.Willem Van Onsem
You can use fromIntegral :: (Integral a, Num b) => a -> b to convert from an Int to any Num (and all Integrals are Nums so that works).gallais

2 Answers

2
votes

If you write something like:

length' :: (Integral a) => a -> a

it means that the function will work for any a where Integral a holds. So that means that a programmer that uses length' could decide to use it as: length' :: Integer -> Integer. Since length however does not return an Integer (but an Int), Haskell can not provide such function length'.

Your function has another problem as well: you call show on a. This means that a has to be an instance of the Show class. So you should add a type constraint Show a. There is no need to restrict to Integral a, since you can use the function for everything that is Show. So the type signature should be:

length' :: Show a => a -> Int
length' = length . show

If you want to give the user the freedom to use any Num n as output type, you can use the genericLength :: Num n => [a] -> n function:

import Data.List(genericLength)

length' :: (Show a, Num n) => a -> n
length' = genericLength . show
1
votes

Int is an instance of integral, but so is, for example, Integer. Your signature is a -> a (where a is an Integral), meaning the type of the result must be the same as the type of the input. So if you apply length' to an Int, the result should be an Int according to your signature, and if you apply it to an Integer, the result should be an Integer.

Since length produces an Int as its result, the result of length' will also always be an Int, which contradicts your signature.

One fix would be to change your signature to Integral a => a -> Int (or the more general Show a => a -> Int) or to add a call to fromIntegral to convert your Int to a number of the appropriate type.