Reputation: 560
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.
Upvotes: 1
Views: 3347
Reputation: 48611
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.
Upvotes: 0
Reputation: 213578
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
Upvotes: 4
Reputation: 3766
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
Upvotes: 0
Reputation: 54068
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 ) )
Upvotes: 1