M Farkas-Dyck
2017-12-14 04:11:03 UTC
I propose to add some new methods of `Enum`:
class Enum a where
...
predMay, succMay :: a -> Maybe a
toEnum' :: Integer -> Maybe a
fromEnum' a -> Integer
Rationale for `fromEnum'` and `toEnum'`:
The docs for `Enum` now say the minimal complete definition is `toEnum` and `fromEnum`, but this is not enough to have sane default instances of the other methods, for example:
data ABC = A | B | C deriving Show
instance Enum ABC where
toEnum 0 = A
toEnum 1 = B
toEnum 2 = C
fromEnum A = 0
fromEnum B = 1
fromEnum C = 2
main = print [A ..] -- [A,B,C,*** Exception: Non-exhaustive patterns in function toEnum
In this case one could merely derive `Enum`, but not in some other cases, e.g. numeric types or GADTs. It is not possible to do better defining `toEnum` and `fromEnum` alone.
If we default-define `toEnum'` and `fromEnum'` and their evil (i.e. partial) syblings in terms of each other, the user need merely define the total methods.
Using `Integer` rather than `Int` allows these methods to not fail for types larger than an `Int`, which are not uncommon on 32-bit systems.
Rationale for `predMay` and `succMay`:
I include these partly for completeness, but `predMay` can not now be defined in general, and `succMay` only cumbersomely in terms of `enumFrom`.
Note: All rationales imply "unless one uses `unsafePerformIO`". I'd rather not, myself.
class Enum a where
...
predMay, succMay :: a -> Maybe a
toEnum' :: Integer -> Maybe a
fromEnum' a -> Integer
Rationale for `fromEnum'` and `toEnum'`:
The docs for `Enum` now say the minimal complete definition is `toEnum` and `fromEnum`, but this is not enough to have sane default instances of the other methods, for example:
data ABC = A | B | C deriving Show
instance Enum ABC where
toEnum 0 = A
toEnum 1 = B
toEnum 2 = C
fromEnum A = 0
fromEnum B = 1
fromEnum C = 2
main = print [A ..] -- [A,B,C,*** Exception: Non-exhaustive patterns in function toEnum
In this case one could merely derive `Enum`, but not in some other cases, e.g. numeric types or GADTs. It is not possible to do better defining `toEnum` and `fromEnum` alone.
If we default-define `toEnum'` and `fromEnum'` and their evil (i.e. partial) syblings in terms of each other, the user need merely define the total methods.
Using `Integer` rather than `Int` allows these methods to not fail for types larger than an `Int`, which are not uncommon on 32-bit systems.
Rationale for `predMay` and `succMay`:
I include these partly for completeness, but `predMay` can not now be defined in general, and `succMay` only cumbersomely in terms of `enumFrom`.
Note: All rationales imply "unless one uses `unsafePerformIO`". I'd rather not, myself.