MANOOL
MANOOL is Not an Object-Oriented Language!”

# Lesson 5

Updated:

Example:

``````{ {extern "manool.org.18/std/0.3/all"} in
: do
{ Rationals in -- demo
: var { A; B } in
A = Rat[1; 2]
B = Rat[3; 4]
Out.WriteLine["A = "; A]
Out.WriteLine["B = "; B]
: for { Op = {array of (+); (-); (*); (/)} } do
Out.WriteLine["A "; Op; " B = "; A.Op[B]]
}
where
Rationals =
{ scope { extern } in
: {extern "manool.org.18/std/0.3/all"} in
: let { _Num; _Den } in
: let { IsRat = {{object utils _Num; _Den} in IsInst} } in -- classification
: let
{ Gcd = -- Greatest Common Divisor of {Num, Den} - snippet of code
{ if Num == 0 then 1 else
: var { A = Abs[Num]; B = Den } in
: do A after
: while A <> B do: if A > B then A = A - B else B = B - A -- Euclidean algorithm
}'
}
in
: let rec
{ Rat = -- construction
{ proc { Num; Den } as
: var { Gcd = Gcd% } in
: object { _Num = Num / Gcd; _Den = Den / Gcd } with
-- extractors
Num = {proc {A} as A[_Num]@}
Den = {proc {A} as A[_Den]@}
-- arithmetic operations
(+) =
{ proc { A; B } as
: unless IsRat[B] signal TypeMismatch else
Rat[Num[A] * Den[B] + Num[B] * Den[A]; Den[A] * Den[B]]
}
(-) =
{ proc { A; B } as
: unless IsRat[B] signal TypeMismatch else
Rat[Num[A] * Den[B] - Num[B] * Den[A]; Den[A] * Den[B]]
}
(*) =
{ proc { A; B } as
: unless IsRat[B] signal TypeMismatch else
Rat[Num[A] * Num[B]; Den[A] * Den[B]]
}
(/) =
{ proc { A; B } as
: unless IsRat[B] signal TypeMismatch else
: unless Num[B] <> 0 signal DivisionByZero else
: if Num[B] > 0 then
Rat[ Num[A] * Den[B]; Den[A] *  Num[B]]
else
Rat[~Num[A] * Den[B]; Den[A] * ~Num[B]]
}
(~) = Neg -- unary minus (arithmetic negation)
Neg =
{ proc { A } as
Rat[~Num[A]; Den[A]]
}
-- comparison
(==) =
{ proc { A; B } as
IsRat[B] & (Num[A] == Num[B]) & (Den[A] == Den[B])
}
(<>) =
{ proc { A; B } as
~IsRat[B] | (Num[A] <> Num[B]) | (Den[A] <> Den[B])
}
(<)  =
{ proc { A; B } as
: unless IsRat[B] signal TypeMismatch else
Num[A] * Den[B] <  Num[B] * Den[A]
}
(<=) =
{ proc { A; B } as
: unless IsRat[B] signal TypeMismatch else
Num[A] * Den[B] <= Num[B] * Den[A]
}
(>)  =
{ proc { A; B } as
: unless IsRat[B] signal TypeMismatch else
Num[A] * Den[B] >  Num[B] * Den[A]
}
(>=) =
{ proc { A; B } as
: unless IsRat[B] signal TypeMismatch else
Num[A] * Den[B] >= Num[B] * Den[A]
}
Order =
{ proc { A; B } as
: unless IsRat[B] signal TypeMismatch else
Order[Num[A] * Den[B]; Num[B] * Den[A]]
}
-- conversions and cloning
Str   = {proc {A} as Str[Num[A]] + "/" + Str[Den[A]]}
Int   = {proc {A} as Num[A] / Den[A]}
Clone = {proc {A} as Rat[Num[A]; Den[A]]}
} -- proc
}
in
: ensure Rat[1; 2] + Rat[ 3; 4] == Rat[ 5; 4] in -- unit tests
: ensure Rat[1; 2] - Rat[ 3; 4] == Rat[~1; 4] in
: ensure Rat[1; 2] * Rat[ 3; 4] == Rat[ 3; 8] in
: ensure Rat[1; 2] / Rat[ 3; 4] == Rat[ 2; 3] in
: ensure Rat[1; 2] / Rat[~3; 4] == Rat[~2; 3] in
: ensure Rat[1; 2] < Rat[ 3; 4] in
: export
Rat = -- construction
{ proc { Num; Den } as
: unless IsI48[Num] & IsI48[Den] signal TypeMismatch else
: unless Den <> 0 signal {if Num <> 0 then DivisionByZero else Undefined} else
: if Den > 0 then Rat[Num; Den] else Rat[~Num; ~Den]
}
IsRat = IsRat -- classification
} -- scope
}
``````

Output:

``````A = 1/2
B = 3/4
A + B = 5/4
A - B = -1/4
A * B = 3/8
A / B = 2/3
``````
Updated: