简体   繁体   中英

Prolog split list by predicate - how to check predicate's result?

I am trying to implement a predicate that splits a list of integers in two given another predicate as an argument. The definition is given as follows:

split(P, L, L1, L2),

where:

P - predicate to split upon
L - list to split
L1 - result list of integers that return true on predicate check
L2 - result list of integers that return false on predicate check

I am trying to modify this code, that splits the list with hardcoded check whether the integer in question is bigger / smaller or equal to X (this works):

split(X, [], [], []).
split(X, [H|T], [H|L1], L2) :- H=<X, split(X, T, L1, L2).
split(X, [H|T], L1, [H|L2]) :- H>X, split(X, T, L1, L2).

For testing purposes, I copied a predicate from RosettaCode to check if the number is even as follows:

even(N) :-
 (between(0, inf, N); integer(N) ),
 0 is N mod 2.

And here is my modification of the above code, but it returns "Syntax error: Operator expected" on last two lines:

split2(P, [], [], []).
split2(P, [H|T], [H|L1], L2) :- P(H), split2(P, T, L1, L2).
split2(P, [H|T], L1, [H|L2]) :- \+ P(H), split2(P, T, L1, L2).

I think my error is in checking whether the predicate returns true or false, but can't find the appropriate way of doing so.

EDIT: Forgot to add my call for this:

 ?- split2(even,[2,7,4,8,-1,5],L1,L2)

You can't call a predicate like this, you need to use call :

?- A = between(0,3,1), A. % OK, because A can be evaluated as it is
A = between(0, 3, 1).

?- A = between, A(0,3,1). % won't work
ERROR: Syntax error: Operator expected
ERROR: A = between, 
ERROR: ** here **
ERROR: A(0,3,1) . 
?- A = between, call(A, 0, 3, 1). % OK, using call
A = between.

?- A = between(0, 3), call(A, 1). % Partial application
A = between(0, 3).

Keep in mind that there are already library predicates that do exactly what you are after, see library(apply) , esp. include/3 . You should also take a look at the implementation , as it is slightly different from what you are doing and doesn't leave choice points behind.

PS: Rearranging the arguments so that the input list is at the front is the first step towards making this deterministic. You also need to get rid of the choice point caused by the two clauses, the one with call(P,H) and the one with \\+ call(P,H) . You can do this with a -> , as in the SWI-Prolog library.

Or maybe you are not bothered by the choice points, or want to make a more general predicate. I am sure that there are solutions here on Stackoverflow on the Prolog tag.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM