rok
rok

Reputation: 2765

Prolog improve code to check user input

I wrote a predicate take(List,N,Result) that returns in Result the first N elements of List. I used two predicates to check if List is actually a list and if List has at least N elements, and I want to output the corresponding errors. This is what I did, that works, but it seems not the best style to me, so I'm asking: how can I improve it? In particular the use of false and the cut seems a too much complicated way to me, but I'm new to Prolog, so I really don't know and asking here.

take(L,N,Result) :-
   checkN(N),
   check(L,N),
   takeaux(L,N,Result).

checkN(N) :-
   (  N > 0
   ;  write('Error N must be positive'),
      false
   ),
   !.

check(L,N) :-
   (  length(L,N1),
      N1 >= N
   ;  write('Error: list has less than '),
      write(N),
      write(' elements'),
      false
   ).

Upvotes: 0

Views: 296

Answers (1)

repeat
repeat

Reputation: 18726

Building on the widely available, tried and tested predicates append/3 and length/2 we define:

take(List,N,Prefix) :-
   append(Prefix,_,List),
   length(Prefix,N).

Sample queries:

?- take([a,b,c,d,e,f,g],3,Prefix).
  Prefix = [a,b,c]                   % succeeds, b
; false.                             % terminates universally

?- take([a,b,c,d,e,f,g],N,Prefix).
  N = 0, Prefix = []
; N = 1, Prefix = [a]
; N = 2, Prefix = [a,b]
; N = 3, Prefix = [a,b,c]
; N = 4, Prefix = [a,b,c,d]
; N = 5, Prefix = [a,b,c,d,e]
; N = 6, Prefix = [a,b,c,d,e,f]
; N = 7, Prefix = [a,b,c,d,e,f,g]
; false.

?- take(List,3,[a,b,c]).
List = [a,b,c|_A].

?- take(List,N,[a,b,c]).
N = 3, List = [a,b,c|_A].

Upvotes: 1

Related Questions