> A decent programming language should have 2 distinct types for floating-point numbers, one for those that cannot be NaNs (to be used only in a program that enables and handles invalid operation exceptions) and one for floating-point numbers that may be NaNs (to be used in programs that disable the invalid operation exception, like most programming languages wrongly do by default).
You've already explained why such a type separation is a bad idea - those types being only usable with specific setup; so, completely utterly breaking composability.
Never mind this making float ops impure & stateful (also forbidding autovectorizing anything with more than one potentially-NaN-producing op if you don't want to break semantics).
Perhaps if hardware supported embedding exception behavior in individual instructions this'd not be insane, but I haven't heard of any architecture having such, making it a complete non-option for sane languages designed to be used.
(there is the option of making compilers insert the necessary fp state transitions, though then you'll have the desire to embed it into calling conventions & function types to avoid transitions when a certain state is expected to stay for a prolonged period of time, which, while certainly possible and would be quite neat to have (also for rounding modes, FTZ/DAZ, etc), is very much in the territory of something almost noone will bother doing, and as such things would just quietly be slower)
While partially-ordered types are neat, what can you really sanely do with a comparison over such? Seems like a rather pointless thing to have.