[mercury-users] Maths and contexts.
Julien Fischer
juliensf at csse.unimelb.edu.au
Sat Apr 21 01:33:28 AEST 2012
On Sat, 21 Apr 2012, Julien Fischer wrote:
> The other limitation of this approach is that you are limited to the
> set of context types that are defined in your program. You cannot
> construct new contexts at runtime.
You can support construction of contexts at runtime and get compile-time
checking of contexts mismatches (at the cost of adding an extra word to
the representation of a number) using existential types. The modified
decimal module below demonstrates this -- I left most of the fields out
of the context to save space. The following test program attempts
to add two decimals that have different contexts associated with them:
:- module test.
:- interface.
:- import_module io.
:- pred main(io::di, io::uo) is det.
:- implementation.
:- import_module decimal2.
:- import_module bool, integer.
main(!IO) :-
Context1 = make_context(integer(30), round_floor, signal(no, no)),
Context2 = make_context(integer(40), round_up, signal(no, no)),
X = to_number(Context1, "1000000"),
Y = to_number(Context2, "2900000"),
Z = X `add` Y,
io.write_string(to_scientific_string(Z), !IO),
io.nl(!IO).
Attempting to compile the above will result in the following compilation
error:
Making Mercury/cs/test.c
test.m:013: In clause for predicate `main'/2:
test.m:013: in unification of variable `Z'
test.m:013: and term `add(X, Y)':
test.m:013: type error in argument(s) of functor `add/2'.
test.m:013: Argument 1 (X) has type `(some [C] decimal2.decimal(C))',
test.m:013: expected type was `decimal2.decimal(C)';
test.m:013: argument 2 (Y) has type `(some [C] decimal2.decimal(C))',
test.m:013: expected type was `decimal2.decimal(C)'.
** Error making `Mercury/cs/test.c'.
The modified code for decimals is:
:- module decimal2.
:- interface.
:- import_module bool.
:- import_module integer.
:- import_module string.
:- type rounding_strategy
---> round_down % mandatory strategies
; round_half_up
; round_half_even
; round_ceiling
; round_floor
; round_half_down % optional strategies
; round_up
; round_05up.
:- type signal
---> signal(
flag :: bool,
trap_enabler :: bool
).
:- typeclass context(C) where [
func precision(decimal(C)) = integer,
func rounding(decimal(C)) = rounding_strategy,
func clamped(decimal(C)) = signal
].
:- some [C] func make_context(integer, rounding_strategy, signal)
= C => context(C).
:- type sign
---> positive
; negative.
:- type decimal(C).
:- func to_scientific_string(decimal(C)) = string <= context(C).
:- func to_engineering_string(decimal(C)) = string <= context(C).
:- func to_number(C, string) = decimal(C) <= context(C).
:- func abs(decimal(C)) = decimal(C) <= context(C).
:- func add(decimal(C), decimal(C)) = decimal(C) <= context(C).
:- implementation.
:- type decimal(C)
---> number(
sign :: sign,
coefficient :: integer,
exponent :: integer,
context :: C
)
; infinity(sign, C)
; quiet_nan(sign, C)
; signalling_nan(sign, C).
:- func get_context(decimal(C)) = C.
get_context(number(_, _, _, C)) = C.
get_context(infinity(_, C)) = C.
get_context(quiet_nan(_, C)) = C.
get_context(signalling_nan(_, C)) = C.
:- type rt_context
---> rt_context(
rtc_prec :: integer,
rtc_round :: rounding_strategy,
rtc_clamped :: signal
).
:- instance context(rt_context) where [
precision(D) = D ^ get_context ^ rtc_prec,
rounding(D) = D ^ get_context ^ rtc_round,
clamped(D) = D ^ get_context ^ rtc_clamped
].
make_context(Prec, Round, Clamp) = rt_context(Prec, Round, Clamp).
:- end_module decimal2.
Julien.
--------------------------------------------------------------------------
mercury-users mailing list
Post messages to: mercury-users at csse.unimelb.edu.au
Administrative Queries: owner-mercury-users at csse.unimelb.edu.au
Subscriptions: mercury-users-request at csse.unimelb.edu.au
--------------------------------------------------------------------------
More information about the users
mailing list