[Haskell-cafe] No Enum for (,), no Enum or Bounded for Either

Tom Ellis tom-lists-haskell-cafe-2013 at jaguarpaw.co.uk
Fri Jun 1 19:20:54 UTC 2018


And to be precise, this seems to work

{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE ScopedTypeVariables #-}

data P a b = P a b deriving (Eq, Bounded, Show)
data E a b = L a | R b deriving (Eq, Show)

instance (Bounded a, Bounded b) => Bounded (E a b) where
  minBound = L minBound
  maxBound = R maxBound

instance forall a b. (Bounded a, Bounded b, Enum a, Enum b) => Enum (E a b) where
  fromEnum = \case
    L a -> fromEnum a
    R b -> fromEnum (maxBound :: a) + fromEnum b + 1

  toEnum n = let m = fromEnum (maxBound :: a)
             in if n <= m
             then L (toEnum n)
             else R (toEnum (n - 1 - m))

instance forall a b. (Bounded a, Bounded b, Enum a, Enum b) => Enum (P a b) where
  fromEnum = \case
    P a b -> fromEnum a * (fromEnum (maxBound :: b) + 1) + fromEnum b
  toEnum n = let (q, r) = quotRem n (fromEnum (maxBound :: b) + 1)
             in P (toEnum q) (toEnum r)

-- Test

data Few = F1 | F2 | F3 deriving (Show, Eq, Bounded, Enum)
data Several = S1 | S2 | S3 | S4 | S5 | S6 | S7 deriving (Show, Eq, Bounded, Enum)

fromEnumP :: P Few Several -> Int
fromEnumP = fromEnum

fromEnumE :: E Few Several -> Int
fromEnumE = fromEnum

idP1 :: P Few Several -> P Few Several
idP1 = toEnum . fromEnum

idP2 :: Int -> Int
idP2 = fromEnumP . toEnum

idE1 :: E Few Several -> E Few Several
idE1 = toEnum . fromEnum

idE2 :: Int -> Int
idE2 = fromEnumE . toEnum

allPs :: [P Few Several]
allPs = P <$> [minBound..maxBound] <*> [minBound..maxBound]

-- > allPs
-- [P F1 S1,P F1 S2,P F1 S3,P F1 S4,P F1 S5,P F1 S6,P F1 S7,P F2 S1,P F2 S2,P F2 S3,P F2 S4,P F2 S5,P F2 S6,P F2 S7,P F3 S1,P F3 S2,P F3 S3,P F3 S4,P F3 S5,P F3 S6,P F3 S7]

allEs :: [E Few Several]
allEs = map L [minBound..maxBound] ++ map R [minBound..maxBound]

-- > allEs
-- [L F1,L F2,L F3,R S1,R S2,R S3,R S4,R S5,R S6,R S7]

test = and [ map idP2 [0..20] == [0..20]
           , map idE2 [0..9] == [0..9]
           , map idP1 allPs == allPs
           , map idE1 allEs == allEs
           ]


-- > test
-- True


On Fri, Jun 01, 2018 at 07:43:05PM +0100, Tom Ellis wrote:
> I made a typo in the second one.  It should be
> 
>       instance (Bounded a, Bounded b) => Bounded (Either a b)
> 
> 
> On Fri, Jun 01, 2018 at 07:32:55PM +0100, Tom Ellis wrote:
> > True.  I think I would propose
> > 
> >     instance (Bounded a, Bounded b, Enum a, Enum b) => Enum (Either a b)
> >     instance (Bounded a, Bounded b) => Enum (Bounded a b)
> >     instance (Bounded a, Bounded b, Enum a, Enum b) => Enum (a, b)
> > 
> > On Fri, Jun 01, 2018 at 02:23:58PM -0400, Li-yao Xia wrote:
> > > One issue is that (Int, Int) is too big to define toEnum/fromEnum.
> > > 
> > > On 06/01/2018 02:10 PM, Tom Ellis wrote:
> > > > I'm a bit surprised that whilst `Either` and `(,)` have instances for `Ord`
> > > > 
> > > > * `(,)` has no instance for `Enum`
> > > > * `Either` has no instance for `Enum` or `Bounded`
> > > > 
> > > > Is there a particular reason for that?  It might be tricky to implement
> > > > 
> > > >      toEnum :: Int -> a
> > > >      fromEnum :: a -> Int
> > > > 
> > > > but in the presence of `Bounded` that should be possible.
> > _______________________________________________
> > Haskell-Cafe mailing list
> > To (un)subscribe, modify options or view archives go to:
> > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
> > Only members subscribed via the mailman list are allowed to post.
> _______________________________________________
> Haskell-Cafe mailing list
> To (un)subscribe, modify options or view archives go to:
> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
> Only members subscribed via the mailman list are allowed to post.


More information about the Haskell-Cafe mailing list