I am implementing an algorithm using Data.Ratio
(convergents of continued fractions).
However, I encounter two obstacles:
1%0
- but this throws a zero denominator exception.a :% b
I was exploring on hackage. An in particular the source seems to be using exactly these features (e.g. defining infinity = 1 :% 0
, or pattern matching for numerator
).
As beginner, I am also confused where it is determined that (%)
, numerator
and such are exposed to me, but not infinity
and (:%)
.
I have already made a dirty workaround using a tuple of integers, but it seems silly to reinvent the wheel about something so trivial. Also would be nice to learn how read the source which functions are exposed.
They aren't exported precisely to prevent people from doing stuff like this. See, the type
data Ratio a = a:%a
contains too many values. In particular, e.g. 2/6
and 3/9
are actually the same number in ℚ and both represented by 1:%3
. Thus, 2:%6
is in fact an illegal value, and so is, sure enough, 1:%0
. Or it might be legal but all functions know how to treat them so 2:%6
is for all observable means equal to 1:%3
– I don't in fact know which of these options GHC chooses, but at any rate it's an implementation detail and could change in future releases without notice.
If the library authors themselves use such values for e.g. optimisation tricks that's one thing – they have after all full control over any algorithmic details and any undefined behaviour that could arise. But if users got to construct such values, it would result in brittle code.
So – if you find yourself starting an algorithm with 1/0
, then you should indeed not use Ratio
at all there but simply store numerator and denominator in a plain tuple, which has no such issues, and only make the final result a Ratio
with %
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With