Idea: "Present at the creation: if I got to redesign Haskell's numbers". TODO: Diagram has an error: `fromEnum` should go to `Int`, not to `Integer`. And we may as well add `toEnum` which goes back the other way. Use one arrow, label it "fromEnum / toEnum". And switch the locations of the `Int` and `Integer` nodes. Did these in the new version, haskell-numbers-handworked.{svg,png} Maybe color the function names in the instance nodes to match their colors. Ditto Is it the case that all functions _not_ shown map !!a^n -> a!! ? Exceptions: Eq == /= Enum enumFrom* Ord compare < <= > >= RealFloat most functions variously RealFrac all the functions are truncations of one sort or another; they produce Integral I could eliminate another crossing if I swapped `Integer` with `Int8`. "I keep getting lost in the maze of Haskell's numeric types. Here's the map I tdrew to help myself out." ---------------------------------------------------------------- Mark Dominus 30 days ago The thing about this that bugs me the most is, you can make Complex Integer and Complex Rational, but you can't do anything with them. I do not understand why there isn't Num a => Num (Complex a) . Mark Dominus 30 days ago Somewhat to my surprise though, I am starting to discern the sense. There are three important properties: Ord (supports ≤), Fractional (supports ÷), and Enum (supports succ/pred). Integral types are Ord | Enum. Floating and Rational types are Ord | Fractional. Complex types are Num but not Ord; that's why Num + Ord is called "Real". Real + Fractional is called "RealFrac". Gaussian integers are a myth. Brandon Chinn 30 days ago It’s odd to me that the Complex docs say: For example, Complex Float’s Ord instance has similar problems to Float’s. when Complex Float doesn’t have an Ord instance… Brandon Chinn 30 days ago I do not understand why there isn’t `Num a => Num (Complex a) `. Does Complex a have a valid definition for all the Num methods? I’m looking at abs in particular, and the law that abs x * signum x == x. Now, should Num have all these methods? Probably not, but that’s a different story… Mark Dominus 30 days ago I think everyone agrees it was a mistake to put abs and signum into Num. It would still be better to have Complex a support Num even if it failed to always obey the obscure abs x * signum x == x law. Another option would be to have Complex a just leave abs and signum undefined. However, I think it would be perfectly reasonable to define abs (a+bi) = sqrt(a²+b²) and signum(a+bi) = (a+bi) ÷ abs(a+bi). Nobody would bat an eyelash. Brandon Chinn 30 days ago oh huh i guess signum doesnt have to be -1/0/1. it just needs to satisfy abs x * signum x == x. so point 4 would probably work Mark Dominus 30 days ago Doesn't work, I used sqrt which requires Floating. :+1: 1 Brandon Chinn 30 days ago in general, having partial functions in Num is not great. that means that the user needs to check that any function they call with a Num constraint doesnt use abs or signum before passing in Complex Int Mark Dominus 30 days ago And guess what? For Floating a => Complex a, abs and signum are defined as I suggested in (4). Mark Dominus 30 days ago ghci> abs (3 :+ 4) 5.0 :+ 0.0 ghci> signum (3 :+ 4) 0.6 :+ 0.8 Brandon Chinn 30 days ago ah! Complex does have a Num instance, it just requires RealFloat a (edited) Mark Dominus 30 days ago Yep. Mark Dominus 30 days ago Even if you leave abs and signum undefined, it doesn't help as much as one would want. I can do Num (Complex a) but I can't get Fractional (Complex a) without Floating a because I can't define recip and / properly without sqrt. It has type sqrt :: Floating a => a -> a but maybe it should have been (Num a, Floating b) => a -> b. But that might make everyone sad because then every time you wrote sqrt x the compiler would throw up its hands and complain that it didn't know what type you wanted sqrt x to be. Mark Dominus 30 days ago I don't think I find this very persuasive. You have the same problem passing any sort of Floating value to a function that might, somewhere along the line, call sqrt and fail because your number is negative. This is the same issue, just less of a problem in practice because (a) Floating is more common than Complex and (b) sqrt is much more common than signum. https://leapyear.slack.com/archives/C6C8XT54G/p1664844301915409?thread_ts=1664838195.860139&cid=C6C8XT54G Brandon Chinn in general, having partial functions in Num is not great. that means that the user needs to check that any function they call with a Num constraint doesnt use abs or signum before passing in Complex Int From a thread in algorithms-team | Oct 3rd | View reply Brandon Chinn 30 days ago sure, but when you, a user, use sqrt or div, you generally know you need to prevent negative numbers or zero. like generally, a function that has a RealFrac constraint would understand that even though an instance exists, you should check these cases. i.e. sqrt and div's partiality is documented behavior but abs and signum doesnt have that defined behavior, so a function would reasonably expect to call abs without an issue, except you broke that trust with an unexpected lack of support for Complex ~