:- module(_,_).

% Types of cuts - Red Cuts
% ------------------------------------

% Another example: 

days_in_year(Y,366) :-
    leap_year(Y),
    !.
days_in_year(_Y,365).

leap_year(Y) :-
    number(Y),
    0 is Y mod 4.

%% Try:
% ?- days_in_year(4,D).
% ?- days_in_year(3,D).
% ?- days_in_year(3,366).
% ?- days_in_year(4,366).
% ?- days_in_year(4,365).
% ?- days_in_year(Y,366).
% Note that the last two produce a wrong answer!

% The best solution: making the cut white by defining the other condition
days_in_year_good(Y,D) :-
    leap_year(Y),
    !,
    D = 366.
days_in_year_good(Y,D) :- 
    standard_year(Y),
    D = 365.

standard_year(Y) :-
    number(Y),
    R is Y mod 4,
    R \= 0.

% Try:
% ?- days_in_year_good(4,D).
% ?- days_in_year_good(4,366).
% ?- days_in_year_good(4,365).
% ?- days_in_year_good(Y,366).
% ?- days_in_year_good(a,D).


% Otherwise, if we still want to save the call to standard_year/1 with
% a cut, we have several solutions:

% Delaying output: 
days_in_year_delay_output(Y,D) :-
    leap_year(Y),
    !,
    D = 366.
days_in_year_delay_output(_Y,365).

% Try:
% ?- days_in_year_delay_output(4,D).
% ?- days_in_year_delay_output(4,365).
% ?- days_in_year_delay_output(4,366).
% ?- days_in_year_delay_output(Y,366).
% Note that the last one still produces a wrong answer!
% This is because we are probably thinking of a 'mode':
% that we provide the year and ask for the number of days. 

% Improvement: we check the 'mode': 
days_in_year_moded(Y,_D) :-
    var(Y),
    !,
    write('{ ERROR: the year must be bound. }\n'),
    abort.
days_in_year_moded(Y,D) :-
    leap_year(Y),
    !,
    D = 366.
days_in_year_moded(_Y,365).

% Try:
% ?- days_in_year_moded(4,D).
% ?- days_in_year_moded(3,D).
% ?- days_in_year_moded(4,365).
% ?- days_in_year_moded(4,366).
% ?- days_in_year_moded(Y,366).
% ?- days_in_year_moded(a,D).

% Even better: ensure mode and type of input and output with an assertion.
% Load assertions package and run-time checking of assertions:
:- use_package([assertions,modes,rtchecks]).

:- pred days_in_year_moded_assrt(+int,-int). 
% :- pred days_in_year_moded_assrt(Y,D) : (int(Y),var(D)).

days_in_year_moded_assrt(Y,D) :-
    leap_year(Y),
    !,
    D=366.
days_in_year_moded_assrt(_Y,365).

% Try:
% ?- days_in_year_moded_assrt(4,D).
% ?- days_in_year_moded_assrt(4,366).
% ?- days_in_year_moded_assrt(4,365).
% ?- days_in_year_moded_assrt(Y,366).
% ?- days_in_year_moded_assrt(a,D).
