Skip to content
heff

std.rational

Rationals: exact fractions of integers, as Racket’s exact numbers are, of any size, as an Int is. A rational is kept in its lowest terms, its denominator above 0, so two equal ones are the same: over 2 4 is over (-1) (-2), one half. Its instances are the prelude’s operators at Rational — x + y, x * y, -x, x < y, max x y, x / y (by 0, 0, as the prelude’s / is) — and divide divides it by what is not 0, over makes one and toFloat is the float nearest it. Import it by a name, import std.rational as Rational, as toFloat is the prelude’s of an Int.

import std.rational as Rational
-- | 1 + 1/2 + 1/3 + ... + 1/n
-- | >>> show (harmonic 4)
-- | "25/12"
harmonic : Int -> Rational.Rational
harmonic n =
List.foldl
(\acc k -> acc + fromMaybe (Rational.fromInt 0) (Rational.over 1 k))
(Rational.fromInt 0)
(List.range 1 n)

Rational

data Rational

A rational: its numerator and its denominator, in its lowest terms (no integer above 1 divides both) and the denominator above 0 — as over makes it, which a rational made by the tag must be too.

over

over : Int -> Int -> Maybe Rational

n over d, in its lowest terms; over 0, nothing.

>>> over 6 (-4)
Just (MkRational (-3) 2)
>>> over 1 0
Nothing

fromInt

fromInt : Int -> Rational

The integer, over 1.

numerator

numerator : Rational -> Int

Its numerator, of its lowest terms: of the sign of the rational.

denominator

denominator : Rational -> Int

Its denominator, of its lowest terms: above 0.

>>> maybe 0 denominator (over 6 (-4))
2

toFloat

toFloat : Rational -> Float64

The float nearest it, correctly rounded: a tie to the even, as std.math’s fromDecimal rounds a decimal — beyond the greatest float, an infinity, and below half the least, 0.0 (of its sign).

>>> List.map toFloat ([fromInt 3, MkRational 1 3, MkRational (-1) 10] : List Rational)
[3.0, 0.3333333333333333, -0.1]
>>> List.map toFloat ([MkRational 1 (Math.tenTo 400), MkRational (Math.tenTo 400) 1] : List Rational)
[0.0, Infinity]

divide

divide : Rational -> Rational -> Maybe Rational

The first divided by the second; by 0, nothing.

>>> divide (MkRational 1 2) (MkRational (-3) 4)
Just (MkRational (-2) 3)
>>> divide (MkRational 1 2) (fromInt 0)
Nothing

instanceEqualityRational

instance instanceEqualityRational : Equality Rational

Equal as fractions: in their lowest terms, of the same terms.

instanceOrderRational

instance instanceOrderRational : Order Rational
>>> List.map (\p -> compare (fst p) (snd p)) ([MkPair (MkRational 1 3) (MkRational 1 2), MkPair (MkRational (-1) 2) (MkRational (-2) 3)] : List (Pair Rational Rational))
Cons LT (Cons GT Nil)

instanceAdditionRational

instance instanceAdditionRational : Addition Rational

instanceSubtractionRational

instance instanceSubtractionRational : Subtraction Rational
>>> (MkRational 1 2 + MkRational 1 3 - MkRational 1 6 : Rational)
MkRational 2 3

instanceMultiplicationRational

instance instanceMultiplicationRational : Multiplication Rational
>>> (MkRational 2 3 * MkRational (-9) 4 : Rational)
MkRational (-3) 2

instanceDivisionRational

instance instanceDivisionRational : Division Rational

Division, total, as the prelude’s / is: by 0, 0 (divide says nothing instead).

>>> ([MkRational 1 2 / MkRational (-3) 4, MkRational 1 2 / fromInt 0] : List Rational)
Cons (MkRational (-2) 3) (Cons (MkRational 0 1) Nil)

instanceNegationRational

instance instanceNegationRational : Negation Rational
>>> (-(MkRational 1 2) : Rational)
MkRational (-1) 2

instanceIsZeroRational

instance instanceIsZeroRational : IsZero Rational

instanceDebugRational

instance instanceDebugRational : Debug Rational

As its tag rebuilds it: MkRational 3 4, a negative numerator in parentheses.

>>> debug (MkRational (-3) 4 : Rational) ^ " " ^ debug (fromInt 2)
"MkRational (-3) 4 MkRational 2 1"

instanceShowRational

instance instanceShowRational : Show Rational

As a reader writes it, as Racket’s: 3/4, -3/4, and an integer alone, 2.

>>> show (MkRational (-3) 4 : Rational) ^ " " ^ show (fromInt 2)
"-3/4 2"