67 lines
2.5 KiB
Prolog
67 lines
2.5 KiB
Prolog
% This implementation uses modern Prolog techniques
|
|
% in order to be an idiomatic solution that uses logical purity, generality and determinism wherever possible:
|
|
% - CLP(Z): constraint logic programming on integers.
|
|
% - library(reif): efficient logical predicates based on 'Indexing dif/2'.
|
|
:- module(fizz_buzz, [main/0, integer_fizzbuzz_below_100/2, integer_fizzbuzz/2]).
|
|
|
|
:- use_module(library(reif)).
|
|
|
|
% for Scryer-Prolog:
|
|
:- use_module(library(clpz)).
|
|
:- use_module(library(between)).
|
|
:- use_module(library(iso_ext)).
|
|
:- use_module(library(si)).
|
|
|
|
% for SWI-Prolog:
|
|
% :- use_module(library(clpfd)).
|
|
|
|
% Prints all solutions to `integer_fizzbuzz_below_100` each on a separate line, in order.
|
|
% Logically-impure shell, as currently there is no logically-pure way to write to a filestream.
|
|
main :-
|
|
forall(integer_fizzbuzz_below_100(_, FizzBuzz), write_line(FizzBuzz)).
|
|
|
|
write_line(Value) :-
|
|
write(Value),
|
|
nl.
|
|
|
|
% Constrains FizzBuzz results to the range 1 <= X <= 100,
|
|
% and (for the 'most general query' where neither X or FizzBuzz is concrete)
|
|
% ensures results are traversed in order low -> high X.
|
|
%
|
|
% ?- integer_fizzbuzz_below_100(X, FizzBuzz) % generate all the results in order
|
|
% ?- integer_fizzbuzz_below_100(27, Result) % Find out what output `27` will produce (it's 'Fizz'.)
|
|
% ?- integer_fizzbuzz_below_100(X, 'Fizz') % generate all the numbers which would print 'Fizz' in order (3, 6, 9, etc).
|
|
% ?- integer_fizzbuzz_below_100(X, Res), integer_si(Res) % generate all the numbers which would print themselves in order (1, 2, 4, 6, 7, 8, 11, etc).
|
|
% ?- integer_fizzbuzz_below_100(X, Res), is_of_type(integer, Res) % SWI-Prolog version doing the same.
|
|
integer_fizzbuzz_below_100(X, FizzBuzz) :-
|
|
between(1, 100, X),
|
|
integer_fizzbuzz(X, FizzBuzz).
|
|
|
|
% States the relationship between a number
|
|
% and its FizzBuzz representation.
|
|
%
|
|
% Because constraints are propagated lazily,
|
|
% prompting this predicate without having constrained `Num`
|
|
% to a particular integer value will give you its definition back.
|
|
% Put differently: This predicate returns the whole solution space at once,
|
|
% and external labeling techniques are required to traverse and concretize this solution space
|
|
% in an order that we like.
|
|
integer_fizzbuzz(Num, FizzBuzz) :-
|
|
if_(Num mod 15 #= 0, FizzBuzz = 'FizzBuzz',
|
|
if_(Num mod 5 #= 0, FizzBuzz = 'Buzz',
|
|
if_(Num mod 3 #= 0, FizzBuzz = 'Fizz',
|
|
Num = FizzBuzz)
|
|
)
|
|
).
|
|
|
|
% Reifiable `#=`.
|
|
#=(X, Y, T) :-
|
|
X #= X1,
|
|
Y #= Y1,
|
|
zcompare(C, X1, Y1),
|
|
eq_t(C, T).
|
|
|
|
eq_t(=, true).
|
|
eq_t(<, false).
|
|
eq_t(>, false).
|