Am I right to conclude that there's no way to compute maxBound - minBound
in Haskell for an arbitrary Enum
and Bounded
type? Or am I missing some trick/hack? This is what I have, which clearly can't work:
difference :: (Enum a, Bounded a) => Int
difference = fromEnum maxBound - fromEnum minBound
Error:
Foo.hs:37:1:
Ambiguous constraint `Enum a'
At least one of the forall'd type variables mentioned by the constraint
must be reachable from the type after the '=>'
In the type signature for `difference': difference :: (Enum a, Bounded a) => Int
Foo.hs:37:1:
Ambiguous constraint `Bounded a'
At least one of the forall'd type variables mentioned by the constraint
must be reachable from the type after the '=>'
In the type signature for `difference': difference :: (Enum a, Bounded a) => Int
I understand why I'm getting that error—there's no actual term in there with type a
, so it can't figure out what a
is. The question is whether there's a way to get around this.
difference :: (Enum a, Bounded a) => a -> Int
difference x = fromEnum (maxBound `asTypeOf` x)
- fromEnum (minBound `asTypeOf` x)
Call it as e.g. difference (undefined :: Char)
.
But note that this will overflow for some types (most notably Int
), so instead use an Integer
result:
difference :: (Enum a, Bounded a) => a -> Integer
difference x = toEnum (fromEnum (maxBound `asTypeOf` x))
- toEnum (fromEnum (minBound `asTypeOf` x))
Use a Proxy
to specify which type you want, and use ScopedTypeVariables
to bring that type into scope in your function definition.
{-# LANGUAGE ScopedTypeVariables #-}
data Proxy a = Proxy
difference :: forall a . (Enum a, Bounded a) => Proxy a -> Int
difference Proxy = fromEnum (maxBound :: a) - fromEnum (minBound :: a)
>>> difference (Proxy :: Proxy Bool)
1
Edit: Using Daniel's suggestion:
data Proxy a = Proxy
difference :: (Enum a, Bounded a) => Proxy a -> Int
difference p = fromEnum (max' p) - fromEnum (min' p) where
max' :: (Bounded a) => Proxy a -> a
max' Proxy = maxBound
min' :: (Bounded a) => Proxy a -> a
min' Proxy = minBound
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With