0
votes

I'm trying to figure out Haskell, but I'm a bit stuck with 'Integral'. From what I gather, Int and Integer are both Integral. However if I try to compile a function like this:

lastNums :: Integral a => a -> a
lastNums a = read ( tail ( show a ) ) :: Integer

I get

Could not deduce (a ~ Integer)
from the context (Integral a)

How do I return an Integral?

Also lets say I have to stick to that function signature.

4

4 Answers

2
votes

Let's read this function type signature in English.

lastNums :: Integral a => a -> a

This means that "Let the caller choose any integral type. The lastNums function can take a value of that type and produce another value of the same type."

However, your definition always returns Integer. According to the type signature, it's supposed to leave that decision up to the caller.

Easiest way to fix this:

lastNums :: Integer -> Integer
lastNums = read . tail . show

There's no shame in defining a monomorphic function. Don't feel it has to be polymorphic just because it can be polymorphic. Often the polymorphic version is more complicated.

Here's another way:

lastNums :: (Integral a, Num a) => a -> a
lastNums = fromInteger . read . tail . show . toInteger

And another way:

lastNums :: (Integral a, Read a, Show a) => a -> a
lastNums = read . tail . show
1
votes

While Int and Integer both implement Integral, Haskell doesn't quite work like that. Instead, if your function returns a value of type Integral a => a, then it must be able to return any value that implements the Integral typeclass. This is different from how most OOP languages use interfaces, in which you can return a specific instance of an interface by casting it to the interface type.

In this case, if you wanted a function lastNums to take an Integral value, convert it to a string, drop the first digits, then convert back to an Integral value, you would have to implement it as

lastNums :: (Integral a, Show a, Read a) => a -> a
lastNums a = read ( tail ( show a ) )
0
votes

You need to be able to Read and Show also. And get rid of the Integer annotation. An Integer is a concrete type while Integral is a typeclass.

lastNums :: (Integral a, Show a, Integral b, Read b) => a -> b
lastNums = read . tail . show 

*Main> lastNums (32 :: Int) :: Integer
2
0
votes

The Integral class offers integer division, and it's a subclass of Ord, so it has comparison too. Thus we can skip the string and just do math. Warning: I haven't tested this yet.

lastNums x | x < 0 = -x
           | otherwise = dropBiggest x

dropBiggest x = db x 0 1

db x acc !val
  | x < 10 = acc
  | otherwise = case x `quotRem` 10 of
                  (q, r) -> db q (acc + r * val) (val * 10)

Side notes: the bang pattern serves to make db unconditionally strict in val. We could add one to acc as well, but GHC will almost certainly figure that out on its own. Last I checked, GHC's native code generator (the default back-end) is not so great at optimizing division by known divisors. The LLVM back-end is much better at that.