Type deduce error for maxBound in a method with Constraints

Viewed 79

I'm going thru Get Programming with Haskell, and try to extend some examples. Having a problem for a function to get the maxBound of Enum:

rotGen :: (Bounded a, Enum a) => a -> (a, Int)
rotGen x = (x, fromEnum (maxBound))

Could not deduce (Bounded a0) arising from a use of ‘maxBound’ from the context: (Bounded a, Enum a)

I understand the problem - fromEnum (maxBound) can't figure out which Bounded type to get the bound. But I don't know to to let the compiler know it's the same type with x.

I tried fromEnum (maxBound :: a) - doesn't work.


Solved.

FYI. This is a cleaner implementation of the ROT13 rotator for Lesson 15 of the Get Programming with Haskell book:

-- gen encoder & decoder for enum 
rotGen :: forall a . (Bounded a, Enum a) => (a -> a, a -> a)
rotGen = (\x -> toEnum ((half + fromEnum x) `mod` max), \x -> toEnum ((upper + fromEnum x) `mod` max))
 where
    max = 1 + fromEnum (maxBound @a)
    half = max `div` 2
    upper = max - half

(though as commented in the thread, language extension is too advanced for a newbie)

2 Answers

You can work with the ScopedTypeVariables and TypeApplications extensions. In that case we define rotGen as:

{-# LANGUAGE ScopedTypeVariables, TypeApplications #-}

rotGen :: forall a . (Bounded a, Enum a) => a -> (a, Int)
rotGen x = (x, fromEnum (maxBound @a))

With the ScopedTypeVariables we can make use of the type parameter a in the expression, and we should use an explicit forall. The TypeApplication extension will specify for what instance we use the maxBound constant.

If you don't want to use extensions for some reason, you can use asTypeOf instead:

rotGen x = (x, fromEnum (maxBound `asTypeOf` x))
Related