Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it impossible to compute the difference between the maxBound and minBound of an Enum type?

Tags:

haskell

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.

like image 499
Luis Casillas Avatar asked Nov 05 '12 21:11

Luis Casillas


2 Answers

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))
like image 95
dave4420 Avatar answered Oct 24 '22 11:10

dave4420


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
like image 45
Gabriella Gonzalez Avatar answered Oct 24 '22 11:10

Gabriella Gonzalez