How to call a predicate from another predicate

#1

Hi friends,

I have these predicates:

deleteall(N,[],[]).
deleteall(N,[N|T],U):-!,deleteall(N,T,U).
deleteall(N,[H|T],[H|U]):-deleteall(N,T,U).
count(N,[],0).
count(N,[N|T],U):-!,count(N,T,U1), U is U1+1.
count(N,[H|T],U):-count(N,T,U).
oc([],[]).
oc([H|T],[[H,X]|Y]):-count(H,[H|T],X), deleteall(H,T,T1), oc(T1,Y).

start:-
write(‘Type your list:’),
read(L1),
call(oc([L1],N)).

How can I read the values from keyboard using the “read” command and pass them to the “oc” predicative?

I really appreciate any help.
:slight_smile:

#2

Welcome to the SWI-Prolog forum. If you double post a question you should provide a link to the other posting.

If you have more questions please ask. :slightly_smiling_face:

#3

Using the same code I posted on StackOverflow

Here is your code with the reading of a list of numbers from user input and running the code.

Code:

read_list(Items) :-
    write('Please enter number, enter "Done" when finished: ' ),
    read_string(user, "\n", "\r", _, Response),
    (
        Response == "Done"
    ->
        Items = []
    ;
        valid_input(Response,Items)
    ).

valid_input(Response,Items) :-
    (
        number_string(Item,Response)
    ->
        % Item was valid
        % so get next number and
        % add to list on backtracking
        read_list(Items0),
        Items = [Item|Items0]
    ;
        % Item was invalid
        % so warn user of invalid number and what they input
        % and get next number.
        % Do not add invalid Item to list on backtracking.
        format('Invalid number: `~w''~n',[Response]),
        read_list(Items0),
        Items = Items0
    ).

deleteall(_N,[],[]).
deleteall(N,[N|T],U) :-
    !,
    deleteall(N,T,U).
deleteall(N,[H|T],[H|U]) :-
    deleteall(N,T,U).

count(_N,[],0).
count(N,[N|T],U) :-
    !,
    count(N,T,U1),
    U is U1 + 1.
count(N,[_H|T],U) :-
    count(N,T,U).

oc([],[]).
oc([H|T],[[H,X]|Y]) :-
    count(H,[H|T],X),
    deleteall(H,T,T1),
    oc(T1,Y).
    
start(Result) :-
    read_list(List),
    oc(List,Result).

Example run:

?- start(Result).
Please enter number, enter "Done" when finished: 1
Please enter number, enter "Done" when finished: 2
Please enter number, enter "Done" when finished: 3
Please enter number, enter "Done" when finished: Done
Result = [[1, 1], [2, 1], [3, 1]] .

Also when your code was loaded it gave warnings like:

Warning: c:/question.pl:66:
        Singleton variables: [N]

Notice in this given code the change of variables, e.g. N to _N; these are anonymous variables.


Here is a variation that uses read/1 as you requested.

read_list(Items) :-
    write('Please enter number followed by period (.), or enter `0.` when finished: ' ), nl,
    read(Response),
    (
        Response == 0
    ->
        Items = []
    ;
        valid_input(Response,Items)
    ).

valid_input(Response,Items) :-
    (
        number(Response),
        Item = Response
    ->
        % Item was valid
        % so get next number and
        % add to list on backtracking
        read_list(Items0),
        Items = [Item|Items0]
    ;
        % Item was invalid
        % so warn user of invalid number and what they input
        % and get next number.
        % Do not add invalid Item to list on backtracking.
        format('Invalid number: `~w''~n',[Response]),
        read_list(Items0),
        Items = Items0
    ).

Example run:

?- start(Result).
Please enter number followed by period (.), or enter `0.` when finished: 
|: 1.
Please enter number followed by period (.), or enter `0.` when finished: 
|: 2.
Please enter number followed by period (.), or enter `0.` when finished: 
|: 3.
Please enter number followed by period (.), or enter `0.` when finished: 
|: 0.
Result = [[1, 1], [2, 1], [3, 1]] .

The reason I prefer to use read_string/5 instead of read/1 is having to enter the period for the term does not seem user friendly to me.

1 Like
#4

Thank you so much EricGT! :slight_smile: