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.