:- module func_default_mode_bug.

% +++++++++++
:- interface.
% +++++++++++

:- import_module io.

:- pred main(io__state, io__state).
:- mode main(di, uo) is det.

% ----------
:- type term
% ----------

--->	parameter(parameter)
;	value(value).


% -----------
:- type bidon
% -----------

--->	bidon(term).


% -----------
:- type value
% -----------

--->	value(float,float).

% ---------------
:- type parameter
% ---------------

--->	parameter(string).


% We declare a typeclass for the constants used in the expressions.
% The user has to provide a null element for the mult operator
% and a null element for the plus operator.
% The user also has to provide a way to test whether term are null
% or not.
% Finally, the user has to provide a way of turning a minus operator
% to a plus. Typically, this is done by doing :
% A - B -> A + ( B * -1 )
% where the constant -1 is up to the user to define...
:- typeclass constant( C)
where	[
	func null_for_mult = C,

	pred is_null_for_mult( C),
	mode is_null_for_mult( in) is semidet,

	func null_for_plus = C,

	pred is_null_for_plus( C),
	mode is_null_for_plus( in) is semidet,

	func minus_one = C
	].

% ++++++++++++++++
:- implementation.
% ++++++++++++++++

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Declares the predicates needed to handle the constants in
% the expressions.

:- instance constant( term)
where	[
	func( null_for_mult/0) is my_null_for_mult,

	pred( is_null_for_mult/1) is my_is_null_for_mult,

	func( null_for_plus/0) is my_null_for_plus,

	pred( is_null_for_plus/1) is my_is_null_for_plus,

	func( minus_one/0) is my_minus_one
	].

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% This function generates a null element for the multiplication.

:- func my_null_for_mult = term.
:- mode my_null_for_mult = out is det.

my_null_for_mult = value( definition_value( 1.0)).


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% This predicate succeeds if the argument is the 1.0 value.

:- pred my_is_null_for_mult( term).
:- mode my_is_null_for_mult( in) is semidet.

my_is_null_for_mult( value( definition_value( 1.0))).


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% This function generates a null element for the addition.

:- func my_null_for_plus = term.
:- mode my_null_for_plus = out is det.

my_null_for_plus = value( definition_value( 0.0)).


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% This predicate succeeds if the argument is the 0.0 value.

:- pred my_is_null_for_plus( term).
:- mode my_is_null_for_plus( in) is semidet.

my_is_null_for_plus( value( definition_value( 0.0))).


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% This function generates a null element for the addition.

:- func my_minus_one = term.
:- mode my_minus_one = out is det.

my_minus_one = value( definition_value( -1.0)).


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% This predicate is used to turn a float or a pair of floats
% into the type value.
:- func definition_value( float) = value.
:- mode definition_value( in) = out is det.

definition_value(X) = value( X, X).

:- func definition_value( float, float) = value.
:- mode definition_value( in, in) = out is det.

definition_value( X, Y) = value( X, Y).


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%:- pred main(io__state, io__state).
%:- mode main(di, uo) is det.

main( In, Out) :-
	io__write( bidon( minus_one), In, Int3),
	io__nl( Int3, Out).
