() Enum Intstance Intentionally Throws Runtime Error

WHY!?

instance Enum () where
    succ _      = errorWithoutStackTrace "Prelude.Enum.().succ: bad argument"
    pred _      = errorWithoutStackTrace "Prelude.Enum.().pred: bad argument"

This seems so stupid! Maybe I’m missing something.

From the Enum docs:

2 Likes

Unit seems like it could be an exception since it is often used as a place holder, but I guess lazyness allows for this to still work as long as it is never resolved.

I think Enum was/is primarily intended to be used through list comprehension notation. Even with that strange instance it does not go wrong, e.g. [() .. ()] and [() ..] both work fine.

1 Like

Might you be interested in todo?

1 Like

question is, why does () have Enum and Bounded instances

instance Bounded () instance does not seem controversial to me. And Enum instances are almost guaranteed to be partial, so one more error does not make a difference.

8 Likes

This is nice! Why isn’t it on hackage?

1 Like

Because @MangoIV is working on its inclusion in base :slight_smile:

3 Likes

I don’t think I have to remind you of “make illegal states unrepresentable”? Whether we are used to a thousand little papercuts doesn’t make it any better.

1 Like

Shouldn’t a partial constraint be added to the declaration then?

What kind of partial constraint?

Like what is used in the safe package

class Enum a where
  pred :: Partial => a -> a
  -- ...

I believe it was @rhendric who pointed out somewhere that, from his experience in PureScript, that Partial constraints are too easy to subvert. I can’t find the relevant post though.

But at least when using them I can tell that they are partial.

You can also get that information from a static analyser, for example GitHub - kowainik/stan: 🕵️ Haskell STatic ANalyser

Adding a Partial constraints is a breaking change, so it would need to go, instead, on new functions. If you’re going to go to those lengths then it’s probably better to make the new functions return Maybe and not be partial. (I would be surprised if such functions didn’t already exist somewhere.)

Relude has truncating versions: Relude.Extra.Enum

I have said that and I stand by it, but for this conversation the Partial in safe is just HasCallStack, which is benign (or at least no worse than using an unannotated partial function). PureScript’s Partial, with its unsafePartial :: forall a. (Partial => a) -> a companion, is a different beast.

1 Like

Ah, I didn’t realise that. If it doesn’t halt compilation unless the Partial constraint is explicitly discarded then it may not satisfy @BebeSparkelSparkel though.