I’ve been studying Prolog for a few weeks ago and something trivial I keep getting stuck on is coming up with solutions using append.
For example, if I have a pattern matching rule that looks something like
pattern( foo(X,Y), L1, L ) :-
% some code to go through a list (where the foo-pattern is)
% and add the pattern to the list L if it matches`
I know that append/3 is the way to go here but.. L starts of unknown i.e. not ground and as we start recursion the list it starts filling up with the matched patterns. However, I always get confused with what initially happens i.e. when L is not ground.
For example, here’s a broken bit of code where we want to get a list of all the matched patterns when the first parameter is a list of possible patterns:
pat([foo(X,Y)|L1], R, L) :-
append(foo(X,Y),R,L),
pat(L1, R, [D|L]).
pat([_|L1], R, L2) :-
pat(L1, R, L2).
Many thanks.
You can probably get away with a solution that doesn’t use
append/3. For example, consider the following predicate,filter/3:The first clause of
filter/3is the base case, where if there is nothing (left) to match in the 2nd argument list, then we get an empty list. Since we didn’t consider thePattern, it is ignored (hence the preceding_against the variable).The second clause of
filter/3tests to see ifPattern, which could be bound to a term (e.g.,foo(X,Y)), can unify with the first element of the list to match,E. The\=operator will succeed when it’s arguments cannot be unified, so if this succeeds, when we didn’t matchEto the pattern, and can throw it away and continue (note the cut!after the test to commit to this branch).The last (third) clause of
filter/3is reliant on the second clause, because it simply passesEonto the last argument listMatchesassuming that it is a match toPattern, because the preceding clause failed to determine that it wasn’t a match. Note that we are appendingEto the list by binding a list structure to the output leaving theMatchessublist unbound; the fullMatcheslist will only be fully bound once it reaches the base case, binding it to the empty list[]once we run out of terms to match in the 2nd argument, creating something like[E1,E2,...,En|[]], where everyE1toEnmatched the pattern; this term is equivalent to the list[E1,E2,...,En].Testing this predicate as follows gives:
Note that everything unifiable with the pattern
foo(X,Y)here was filtered out intoLas necessary.One final note: In your code, the call
append(foo(X,Y),R,L)will always fail, becauseappend/3operates on lists only; you probably wanted to callappend([foo(X,Y)],R,L)instead, but in that case, you an simply useL = [foo(X,Y)|R]as a shorthand instead.EDIT: To match your particular case where you have a list of possible patterns to match and filter on, here is another predicate,
filter_list/3:Note that
filter_list/3depends on my previous definition offilter/3, and is implemented using exactly the same strategy: ifEdoesn’t match any of thePatterns(i.e., this is the case wherefilter(E, Patterns, [])succeeds), then we forgetEand continue, else (last clause) we keep it. Testing gives us: