Science
Copyright © 2024 Jiri Kriz, www.nosco.ch

6    Built-in Predicates

Solution of Exercise 6

6.1    Higher-order Predicates

abolish( F, A) :- functor( Term, F, A), retract_all( Term).

retract_all( X) :- retract( X), fail.
retract_all( X) :- retract( X :- _), fail.
retract_all( _).

/* Testing */
assert_test :-
	assert(test(1)),
	assert(test(2)),
	assert(test(3) :- test(a, b)), 
	assert(test(a, b)).

/* Test
?- assert_test.
?- test(X). => X = 1; X = 2; X = 3.
?- abolish(test, 1).
?- test(X). => false
?- test(X, Y). => X = a, Y = b
*/


filter( P, [ X| Xs], [ X| Ys]) :- 
    F =.. [P, X], call( F), !, 
    filter( P, Xs, Ys).
filter( P, [ _| Xs], Ys) :- filter( P, Xs, Ys).
filter( _, [], []).

pos( X) :- X > 0.
neg( X) :- X < 0.

/*
?- filter( pos, [ 1, -1, 2, -2], Y)    => Y = [ 1, 2].
?- filter( neg, [ 1, -1, 2, -2], Y)    => Y = [ -1, -2].
*/

Back to example 6.1

6.2    Memoization

:- dynamic fibo/2.  /* a directive for SWI Prolog */

fibo( 0, 0).
fibo( 1, 1).
fibo( N, F) :- 
    N > 1, N1 is N - 1, N2 is N - 2,
    fibo( N1, F1), fibo( N2, F2), F is F1 + F2,
    asserta( fibo( N, F) :- !).
     
/* Iterative solution */
fibo_iter(Counter, F2, F1, Result) :-
    Counter > 0,
    Sum is F2 + F1,
    F2_new = F1,
    F1_new = Sum,
    Counter1 is Counter - 1,
    fibo_iter(Counter1, F2_new, F1_new, Result).
fibo_iter(0, F2, F1, Result) :-
    Result = F1.
    
fibo_iter(0, 0).
fibo_iter(1, 1).
fibo_iter(N, F) :-
    N > 1,
    Counter is N - 1,
    fibo_iter(Counter, 0, 1, F).
    
/* A more elegant formulation : 
fibo_iter(Counter, F2, F1, Result) :-
    Counter > 0,
    Sum is F2 + F1,
    Counter1 is Counter - 1,
    fibo_iter(Counter1, F1, Sum, Result).
fibo_iter(0, _, Result, Result).
*/


Back to example 6.2

6.3    User Interaction

/* Database */
:- dynamic dist/3.  /* a directive for SWI Prolog */
dist( zuerich, baden, 22).
dist( baden, basel, 83).
/* End Database */

/* Main Goal - type distances into the Prolog console */
distances :-
    nl, write( 'Input: d( City1, City2).'),
    nl, write( 'Quit: exit.'),
    repeat,
		nl, write( 'Input: '),
		read( Input), 
    process_input( Input), !.


d( X, Y, D) :- dist( X, Y, D).
d( X, Y, D) :- dist( Y, X, D). 

process_input( exit) :- !.
process_input( d( S1, S2)) :- distance( S1, S2, _), fail.

output( S1, S2, D) :-
    nl, write( 'The distance between '), write( S1), write( ' and '), write( S2), 
    write( ' is '), write( D), write( ' km ').

distance( S1, S2, D) :- d( S1, S2, D), output( S1, S2, D), !.
distance( S1, S2, D) :- ask_user( S1, S2, D), !.

ask_user( S1, S2, D) :-
    nl, write( 'I do not know. Please tell me:'), 
    read( DR), process_answer( S1, S2, D, DR).

process_answer( S1, S2, D, DR) :-
    number( DR), !, D = DR, assert( dist( S1, S2, D)),
    nl, write( 'Thank you. I confirm:'), output( S1, S2, D).
process_answer( _, _, _, no).
process_answer( _, _, _, eof).
process_answer( S1, S2, D, _) :- 
    nl, write( '*** Invalid Input ***'), ask_user( S1, S2, D).

Back to example 6.3

6.4    Counter

init( C, V) :- retractall( counter( C, _)), 
               assert( counter( C, V)), !.
get( C, V)  :- counter( C, V).
inc( C)     :- retract( counter( C, N)), N1 is N + 1, 
               assert( counter( C, N1)), !.
dec( C)     :- retract( counter( C, N)), N1 is N - 1, 
               assert( counter( C, N1)), !.
del( C)     :- retract( counter( C, _)).

Back to example 6.4

6.5    Transformation of Facts into List Arguments

/* bagof and setof are predefined in SWI Prolog,
so we call them bag_of and set_of */

bag_of( X, P, _) :-
    asserta( found( mark)), 
    call( P), 
    asserta( found(X)), 
    fail.
bag_of( _, _, B) :- 
    collect( [], B).

collect( B, BB) :- 
    retract( found( X)), 
    ( X == mark -> BB = B
                ;  collect( [ X| B], BB)
    ), !.

/* The following set_of sorts the element of the list S */

set_of( X, P, S) :-
    bag_of( X, P, L),
    sort1( L, S).
     
sort1( [], []).
sort1( [ X1| Xs], Y) :- 
    sort1( Xs, Ys), 
    insert1( X1, Ys, Y).

insert1( X, [], [ X]).
insert1( X, [ Y1| Ys], [ X, Y1| Ys]) :- X < Y1.
insert1( X, [ Y1| Ys], [ Y1| Zs])    :- X > Y1, insert1( X, Ys, Zs).
insert1( X, [ X| Ys], [ X| Ys]).

/* Test data */
a(4).
a(1).
a(5).
a(3).
a(4).
a(1).

/* Test queries:
?- bag_of( X, a(X), B).         => B = [4, 1, 5, 3, 4, 1]
?- bag_of( b(c,X), a(X), B).    => B = [[b(c, 4), b(c, 1), b(c, 5), b(c, 3), b(c, 4), b(c, 1)]
?- bag_of( X, (a(X), X>2), B).  => B = [4, 5, 3, 4]

?- set_of( X, a(X), S).         => S = [1, 3, 4, 5]
?- set_of( b(c,X), a(X), S).    => Exception: S contains non-numerical elements
?- set_of( X, (a(X), X>2), S).  => S = [[3, 4, 5]
*/

Back to example 6.5