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.
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.
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.
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.
This is nice! Why isn’t it on hackage?
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.
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.
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.