Packages

A featureful rational number type for Gleam.

Current section

Files

Jump to
glat src glat.erl
Raw

src/glat.erl

-module(glat).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([from_int/1, from_float_check/1, to_int/1, to_int_floor/1, to_float/1, to_string/1, is_negative/1, is_positive/1, absolute_value/1, remainder/1, modulo/1, fraction/1, fraction_floor/1, floor/1, ceiling/1, negate/1, compare/2, round/1, add/2, subtract/2, multiply/2, max/2, min/2, clamp/3, digits/2, map_num/2, new_check/2, random_check/1, parse_check/1, flip_check/1, divide_check/2, int_power_check/2, undigits_check/2, map_den_check/2, map_both_check/2, map_seperate_check/3, new/2, from_float/1, parse/1, reduce/1, flip/1, undigits/2, unwrap/1, random/1, divide/2, square_root_check/1, square_root/1, power_check/2, power/2, int_power/2, map_den/2, map_both/2, map_seperate/3, product/1, sum/1]).
-export_type([rational/0, undigits_error/0]).
-type rational() :: {rational, integer(), integer()}.
-type undigits_error() :: base_error | zero_error.
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 36).
-spec from_int(integer()) -> rational().
from_int(Num) ->
{rational, Num, 1}.
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 57).
-spec from_float_check(float()) -> {ok, rational()} | {error, nil}.
from_float_check(F) ->
case F of
+0.0 ->
{error, nil};
_ ->
_assert_subject = begin
_pipe = gleam@float:to_string(F),
gleam@string:split(_pipe, <<"."/utf8>>)
end,
[Whole_str, Fract_str] = case _assert_subject of
[_, _] -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail,
module => <<"glat"/utf8>>,
function => <<"from_float_check"/utf8>>,
line => 61})
end,
Fract_str@1 = case Fract_str of
<<"0"/utf8>> ->
<<""/utf8>>;
X ->
X
end,
Power = gleam@string:length(Fract_str@1),
_assert_subject@1 = gleam@int:parse(
<<Whole_str/binary, Fract_str@1/binary>>
),
{ok, Num} = case _assert_subject@1 of
{ok, _} -> _assert_subject@1;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail@1,
module => <<"glat"/utf8>>,
function => <<"from_float_check"/utf8>>,
line => 70})
end,
Den = glat@util:int_power(10, Power),
{ok, {rational, Num, Den}}
end.
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 99).
-spec do_parse(binary()) -> {ok, {integer(), integer()}} | {error, nil}.
do_parse(Str) ->
case begin
_pipe = Str,
gleam@string:split(_pipe, <<"/"/utf8>>)
end of
[Num, Den] ->
gleam@result:'try'(
gleam@int:parse(Num),
fun(Num@1) ->
gleam@result:'try'(
gleam@int:parse(Den),
fun(Den@1) -> {ok, {Num@1, Den@1}} end
)
end
);
_ ->
{error, nil}
end.
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 112).
-spec to_int(rational()) -> integer().
to_int(Rat) ->
case erlang:element(3, Rat) of
0 -> 0;
Gleam@denominator -> erlang:element(2, Rat) div Gleam@denominator
end.
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 118).
-spec to_int_floor(rational()) -> integer().
to_int_floor(Rat) ->
_pipe = erlang:element(2, Rat),
_pipe@1 = gleam@int:floor_divide(_pipe, erlang:element(3, Rat)),
gleam@result:unwrap(_pipe@1, 0).
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 123).
-spec to_float(rational()) -> float().
to_float(Rat) ->
case gleam@int:to_float(erlang:element(3, Rat)) of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> gleam@int:to_float(erlang:element(2, Rat)) / Gleam@denominator
end.
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 128).
-spec to_string(rational()) -> binary().
to_string(Rat) ->
<<<<(gleam@int:to_string(erlang:element(2, Rat)))/binary, "/"/utf8>>/binary,
(gleam@int:to_string(erlang:element(3, Rat)))/binary>>.
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 132).
-spec is_negative(rational()) -> boolean().
is_negative(Rat) ->
erlang:element(2, Rat) < 0.
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 136).
-spec is_positive(rational()) -> boolean().
is_positive(Rat) ->
erlang:element(2, Rat) >= 0.
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 147).
-spec absolute_value(rational()) -> rational().
absolute_value(Rat) ->
erlang:setelement(2, Rat, gleam@int:absolute_value(erlang:element(2, Rat))).
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 190).
-spec remainder(rational()) -> integer().
remainder(Rat) ->
_assert_subject = gleam@int:remainder(
erlang:element(2, Rat),
erlang:element(3, Rat)
),
{ok, Num} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail,
module => <<"glat"/utf8>>,
function => <<"remainder"/utf8>>,
line => 191})
end,
Num.
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 197).
-spec modulo(rational()) -> integer().
modulo(Rat) ->
_assert_subject = gleam@int:modulo(
erlang:element(2, Rat),
erlang:element(3, Rat)
),
{ok, Num} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail,
module => <<"glat"/utf8>>,
function => <<"modulo"/utf8>>,
line => 198})
end,
Num.
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 204).
-spec fraction(rational()) -> rational().
fraction(Rat) ->
{rational, remainder(Rat), erlang:element(3, Rat)}.
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 210).
-spec fraction_floor(rational()) -> rational().
fraction_floor(Rat) ->
{rational, modulo(Rat), erlang:element(3, Rat)}.
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 215).
-spec floor(rational()) -> rational().
floor(Rat) ->
case remainder(Rat) of
0 ->
Rat;
Rem ->
case is_positive(Rat) of
true ->
{rational,
erlang:element(2, Rat) - Rem,
erlang:element(3, Rat)};
false ->
{rational,
(erlang:element(2, Rat) - Rem) - erlang:element(3, Rat),
erlang:element(3, Rat)}
end
end.
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 229).
-spec ceiling(rational()) -> rational().
ceiling(Rat) ->
case remainder(Rat) of
0 ->
Rat;
Rem ->
case is_positive(Rat) of
true ->
{rational,
(erlang:element(2, Rat) - Rem) + erlang:element(3, Rat),
erlang:element(3, Rat)};
false ->
{rational,
erlang:element(2, Rat) - Rem,
erlang:element(3, Rat)}
end
end.
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 249).
-spec negate(rational()) -> rational().
negate(Rat) ->
{rational, - erlang:element(2, Rat), erlang:element(3, Rat)}.
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 253).
-spec compare(rational(), rational()) -> gleam@order:order().
compare(Lhs, Rhs) ->
gleam@int:compare(
erlang:element(2, Lhs) * erlang:element(3, Rhs),
erlang:element(3, Lhs) * erlang:element(2, Rhs)
).
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 241).
-spec round(rational()) -> rational().
round(Rat) ->
_pipe = Rat,
case compare(Rat, {rational, 1, 2}) of
gt ->
fun ceiling/1;
eq ->
fun ceiling/1;
lt ->
fun floor/1
end(_pipe).
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 257).
-spec add(rational(), rational()) -> rational().
add(Lhs, Rhs) ->
case erlang:element(3, Lhs) =:= erlang:element(3, Rhs) of
true ->
{rational,
erlang:element(2, Lhs) + erlang:element(2, Rhs),
erlang:element(3, Lhs)};
false ->
{rational,
(erlang:element(2, Lhs) * erlang:element(3, Rhs)) + (erlang:element(
3,
Lhs
)
* erlang:element(2, Rhs)),
erlang:element(3, Lhs) * erlang:element(3, Rhs)}
end.
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 265).
-spec subtract(rational(), rational()) -> rational().
subtract(Lhs, Rhs) ->
case erlang:element(3, Lhs) =:= erlang:element(3, Rhs) of
true ->
{rational,
erlang:element(2, Lhs) - erlang:element(2, Rhs),
erlang:element(3, Lhs)};
false ->
{rational,
(erlang:element(2, Lhs) * erlang:element(3, Rhs)) - (erlang:element(
3,
Lhs
)
* erlang:element(2, Rhs)),
erlang:element(3, Lhs) * erlang:element(3, Rhs)}
end.
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 273).
-spec multiply(rational(), rational()) -> rational().
multiply(Lhs, Rhs) ->
{rational,
erlang:element(2, Lhs) * erlang:element(2, Rhs),
erlang:element(3, Lhs) * erlang:element(3, Rhs)}.
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 294).
-spec max(rational(), rational()) -> rational().
max(Rat1, Rat2) ->
case compare(Rat1, Rat2) of
lt ->
Rat2;
_ ->
Rat1
end.
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 303).
-spec min(rational(), rational()) -> rational().
min(Rat1, Rat2) ->
case compare(Rat1, Rat2) of
gt ->
Rat2;
_ ->
Rat1
end.
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 312).
-spec clamp(rational(), rational(), rational()) -> rational().
clamp(Rat, Min_bound, Max_bound) ->
_pipe = Rat,
_pipe@1 = min(_pipe, Max_bound),
max(_pipe@1, Min_bound).
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 361).
-spec digits(rational(), integer()) -> {ok, {list(integer()), list(integer())}} |
{error, nil}.
digits(Rat, Base) ->
case {gleam@int:digits(erlang:element(2, Rat), Base),
gleam@int:digits(erlang:element(3, Rat), Base)} of
{{ok, Num}, {ok, Den}} ->
{ok, {Num, Den}};
{_, _} ->
{error, nil}
end.
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 414).
-spec map_num(rational(), fun((integer()) -> integer())) -> rational().
map_num(Rat, Fun) ->
{rational, Fun(erlang:element(2, Rat)), erlang:element(3, Rat)}.
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 462).
-spec shift_negative(rational()) -> rational().
shift_negative(Rat) ->
case erlang:element(3, Rat) < 0 of
true ->
{rational,
gleam@int:negate(erlang:element(2, Rat)),
gleam@int:negate(erlang:element(3, Rat))};
false ->
Rat
end.
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 23).
-spec new_check(integer(), integer()) -> {ok, rational()} | {error, nil}.
new_check(Num, Den) ->
case Den of
0 ->
{error, nil};
_ ->
{ok,
begin
_pipe = {rational, Num, Den},
shift_negative(_pipe)
end}
end.
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 44).
-spec random_check(integer()) -> {ok, rational()} | {error, nil}.
random_check(Den) ->
new_check(gleam@int:random(gleam@int:absolute_value(Den) + 1), Den).
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 85).
-spec parse_check(binary()) -> {ok, rational()} | {error, nil}.
parse_check(Str) ->
gleam@result:'try'(
do_parse(Str),
fun(_use0) ->
{Num, Den} = _use0,
new_check(Num, Den)
end
).
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 154).
-spec flip_check(rational()) -> {ok, rational()} | {error, nil}.
flip_check(Rat) ->
new_check(erlang:element(3, Rat), erlang:element(2, Rat)).
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 281).
-spec divide_check(rational(), rational()) -> {ok, rational()} | {error, nil}.
divide_check(Lhs, Rhs) ->
_pipe = flip_check(Rhs),
gleam@result:map(_pipe, fun(_capture) -> multiply(Lhs, _capture) end).
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 336).
-spec int_power_check(integer(), integer()) -> {ok, rational()} | {error, nil}.
int_power_check(Base, Exponent) ->
case Exponent >= 0 of
true ->
_pipe = glat@util:int_power(Base, Exponent),
_pipe@1 = from_int(_pipe),
{ok, _pipe@1};
false ->
new_check(1, glat@util:int_power(Base, gleam@int:negate(Exponent)))
end.
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 396).
-spec do_undigits({list(integer()), list(integer())}, integer()) -> {ok,
rational()} |
{error, undigits_error()}.
do_undigits(Tup, Base) ->
gleam@result:'try'(
begin
_pipe = gleam@int:undigits(erlang:element(1, Tup), Base),
gleam@result:replace_error(_pipe, base_error)
end,
fun(Num) ->
gleam@result:'try'(
begin
_pipe@1 = gleam@int:undigits(erlang:element(2, Tup), Base),
gleam@result:replace_error(_pipe@1, base_error)
end,
fun(Den) -> _pipe@2 = new_check(Num, Den),
gleam@result:replace_error(_pipe@2, zero_error) end
)
end
).
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 373).
-spec undigits_check({list(integer()), list(integer())}, integer()) -> {ok,
rational()} |
{error, nil}.
undigits_check(Tup, Base) ->
_pipe = do_undigits(Tup, Base),
gleam@result:nil_error(_pipe).
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 418).
-spec map_den_check(rational(), fun((integer()) -> integer())) -> {ok,
rational()} |
{error, nil}.
map_den_check(Rat, Fun) ->
new_check(erlang:element(2, Rat), Fun(erlang:element(3, Rat))).
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 429).
-spec map_both_check(rational(), fun((integer()) -> integer())) -> {ok,
rational()} |
{error, nil}.
map_both_check(Rat, Fun) ->
new_check(Fun(erlang:element(2, Rat)), Fun(erlang:element(3, Rat))).
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 440).
-spec map_seperate_check(
rational(),
fun((integer()) -> integer()),
fun((integer()) -> integer())
) -> {ok, rational()} | {error, nil}.
map_seperate_check(Rat, Fun1, Fun2) ->
new_check(Fun1(erlang:element(2, Rat)), Fun2(erlang:element(3, Rat))).
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 31).
-spec new(integer(), integer()) -> rational().
new(Num, Den) ->
_pipe = new_check(Num, Den),
gleam@result:unwrap(_pipe, {rational, 0, 1}).
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 78).
-spec from_float(float()) -> rational().
from_float(F) ->
_pipe = from_float_check(F),
gleam@result:unwrap(_pipe, {rational, 0, 1}).
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 94).
-spec parse(binary()) -> {ok, rational()} | {error, nil}.
parse(Str) ->
gleam@result:map(
do_parse(Str),
fun(_use0) ->
{Num, Den} = _use0,
new(Num, Den)
end
).
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 141).
-spec reduce(rational()) -> rational().
reduce(Rat) ->
Gcd = glat@util:gcd(erlang:element(2, Rat), erlang:element(3, Rat)),
new(case Gcd of
0 -> 0;
Gleam@denominator -> erlang:element(2, Rat) div Gleam@denominator
end, case Gcd of
0 -> 0;
Gleam@denominator@1 -> erlang:element(3, Rat) div Gleam@denominator@1
end).
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 161).
-spec flip(rational()) -> rational().
flip(Rat) ->
_pipe = flip_check(Rat),
gleam@result:unwrap(_pipe, {rational, 0, 1}).
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 385).
-spec undigits({list(integer()), list(integer())}, integer()) -> {ok,
rational()} |
{error, nil}.
undigits(Tup, Base) ->
case do_undigits(Tup, Base) of
{ok, Rat} ->
{ok, Rat};
{error, zero_error} ->
{ok, {rational, 0, 1}};
_ ->
{error, nil}
end.
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 457).
-spec unwrap({ok, rational()} | {error, nil}) -> rational().
unwrap(Res) ->
gleam@result:unwrap(Res, {rational, 0, 1}).
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 52).
-spec random(integer()) -> rational().
random(Den) ->
unwrap(random_check(Den)).
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 289).
-spec divide(rational(), rational()) -> rational().
divide(Lhs, Rhs) ->
unwrap(divide_check(Lhs, Rhs)).
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 169).
-spec square_root_check(rational()) -> {ok, rational()} | {error, nil}.
square_root_check(Rat) ->
case erlang:element(2, Rat) of
0 ->
{ok, Rat};
_ ->
gleam@result:'try'(
gleam@int:square_root(erlang:element(2, Rat)),
fun(Num) ->
gleam@result:'try'(
gleam@int:square_root(erlang:element(3, Rat)),
fun(Den) ->
{ok, divide(from_float(Num), from_float(Den))}
end
)
end
)
end.
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 184).
-spec square_root(rational()) -> rational().
square_root(Rat) ->
_pipe = square_root_check(Rat),
gleam@result:unwrap(_pipe, {rational, 0, 1}).
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 322).
-spec power_check(rational(), integer()) -> {ok, rational()} | {error, nil}.
power_check(Rat, Exponent) ->
gleam@result:'try'(
int_power_check(erlang:element(2, Rat), Exponent),
fun(Num) ->
gleam@result:map(
int_power_check(erlang:element(3, Rat), Exponent),
fun(Den) -> divide(Num, Den) end
)
end
).
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 330).
-spec power(rational(), integer()) -> rational().
power(Rat, Exponent) ->
unwrap(power_check(Rat, Exponent)).
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 345).
-spec int_power(integer(), integer()) -> rational().
int_power(Base, Exponent) ->
unwrap(int_power_check(Base, Exponent)).
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 425).
-spec map_den(rational(), fun((integer()) -> integer())) -> rational().
map_den(Rat, Fun) ->
unwrap(map_den_check(Rat, Fun)).
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 436).
-spec map_both(rational(), fun((integer()) -> integer())) -> rational().
map_both(Rat, Fun) ->
unwrap(map_both_check(Rat, Fun)).
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 448).
-spec map_seperate(
rational(),
fun((integer()) -> integer()),
fun((integer()) -> integer())
) -> rational().
map_seperate(Rat, Fun1, Fun2) ->
unwrap(map_seperate_check(Rat, Fun1, Fun2)).
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 350).
-spec product(list(rational())) -> rational().
product(Rats) ->
gleam@list:fold(Rats, {rational, 1, 1}, fun multiply/2).
-file("/home/benjamin/building/gleam/glatv1/src/glat.gleam", 355).
-spec sum(list(rational())) -> rational().
sum(Rats) ->
gleam@list:fold(Rats, {rational, 1, 1}, fun add/2).