<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body dir="auto"><span style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0);">Nothing indicates that minBound is >= 0.</span><div style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0);"><br></div><div style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0);">So if you want to deal with a modulus properly you need to deal with a modulus of something like maxBound - minBound + 1 (after appropriately upcasting intermediate results to a large enough type to contain that range). </div><div style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0);"><br></div><div style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0);">You also run into range issues pretty early on, and then scenarios like the instances for Float that are even wonkier.</div><div style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0);"><br></div><div style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0);">If toEnum/fromEnum went to a larger type (Integer or Natural) and we didn't have the wonkier Float instances and the like this would be a much easier sell. As it is I find myself rather uncomfortable with the shakiness of the foundations this thing rests upon.</div><br><div dir="ltr">Sent from my iPhone</div><div dir="ltr"><br><blockquote type="cite">On May 12, 2021, at 10:53 AM, Sandy Maguire <sandy@sandymaguire.me> wrote:<br><br></blockquote></div><blockquote type="cite"><div dir="ltr"><div dir="ltr"><div class="gmail_quote"><div><div>Hi all,<br><br></div><div>Found myself puzzled the other day when I wanted an <span style="font-family:monospace">(Enum a, Enum b) => Enum (a, b)</span> instance, and was distraught that it didn't exist.</div><div><br></div><div>The following is a reasonable implementation:<br><br><br><span style="font-family:monospace">instance (Bounded b, Enum a, Enum b) => Enum (a, b) where<br>  fromEnum (a, b) = (fromEnum (maxBound @b) + 1) * fromEnum a + fromEnum b<br>  toEnum n =<br>    let bound = fromEnum (maxBound @b) + 1<br>        b = n `rem` bound<br>        a = n `div` bound<br>     in (toEnum a, toEnum b)</span><br><br></div><div>And, while we're at it, might as well add canonical instances for Either:<br><br><br><span style="font-family:monospace">instance (Bounded a, Bounded b) => Bounded (Either a b) where<br>  minBound = Left minBound<br>  maxBound = Right maxBound<br><br>instance (Bounded a, Enum a, Enum b) => Enum (Either a b) where<br>  toEnum i =<br>    let bound = fromEnum (maxBound @a) + 1<br>     in case i < bound of<br>          True -> Left $ toEnum i<br>          False -> Right $ toEnum $ i - bound<br>  fromEnum (Left a) = fromEnum a<br>  fromEnum (Right b) = fromEnum b + fromEnum (maxBound @a) + 1</span><br></div><div><br></div><div>Are there any reasons these instances are missing from base?<br><br></div><div>Cheers,<br></div><div>Sandy<br></div></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div><br></div></div>
</blockquote></div></div>
<span>_______________________________________________</span><br><span>Libraries mailing list</span><br><span>Libraries@haskell.org</span><br><span>http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries</span><br></div></blockquote></body></html>