%% -*- mode: mercury; prolog-indent-width: 2; -*- :- module modular_arithmetic_task. :- interface. :- import_module io. :- pred main(io::di, io::uo) is det. :- implementation. :- import_module exception. :- import_module integer. :- type modular_integer ---> modular(integer, integer) ; ordinary(integer). :- func operate((func(integer, integer) = integer), modular_integer, modular_integer) = modular_integer. operate(OP, modular(A, M1), modular(B, M2)) = C :- if (M1 = M2) then (C = modular(mod(OP(A, B), M1), M1)) else throw("mismatched moduli"). operate(OP, modular(A, M), ordinary(B)) = C :- C = modular(mod(OP(A, B), M), M). operate(OP, ordinary(A), modular(B, M)) = C :- C = modular(mod(OP(A, B), M), M). operate(OP, ordinary(A), ordinary(B)) = C :- C = ordinary(OP(A, B)). :- func '+'(modular_integer, modular_integer) = modular_integer. (A : modular_integer) + (B : modular_integer) = operate(+, A, B). :- func pow(modular_integer, modular_integer) = modular_integer. pow(A : modular_integer, B : modular_integer) = operate(pow, A, B). :- pred display(modular_integer::in, io::di, io::uo) is det. display(X, !IO) :- if (X = modular(A, _)) then print(A, !IO) else if (X = ordinary(A)) then print(A, !IO) else true. :- func f(modular_integer) = modular_integer. f(X) = Y :- Y = pow(X, ordinary(integer(100))) + X + ordinary(integer(1)). main(!IO) :- X1 = ordinary(integer(10)), X2 = modular(integer(10), integer(13)), print("No modulus: ", !IO), display(f(X1), !IO), nl(!IO), print("modulus 13: ", !IO), display(f(X2), !IO), nl(!IO). :- end_module modular_arithmetic_task.