This library provides predicates to do pattern matching in a way that complements and
expands on library(reif).
Tested on Scryer Prolog 0.10.
The core predicate of this library is pattern_match_t/3. It has a non-reified version
pattern_match/2, along with some operator aliases (=~)/3 (the pattern is always in
the side of the ~).
The pattern consists of a term that is a clean representation of what you want to match. You always need to specify how a term will be matched with a wrapping functor. All of the wrapping functors have operators provided for ergonomics.
Matches a ground term. Doesn't need to be atomic.
?- a(1,2,3) =~ +a(1,2,3).
true.
?- =~(a(1,2,3), +a(1,2,3), T).
T = true.Binds a variable. This does normal unification, not reified unification like (?)/1.
?- a(1,2,3) =~ -X.
X = a(1,2,3).
?- =~(a(1,2,3), -X, T).
X = a(1,2,3), T = true.Does reified unification. If used in a non-reified predicate, it's basically the same
thing as (-)/1, but creates a spurious choice point. When used in a reified
predicate, does the unification like (=)/3, exploring the dif/2 case on backtracking.
?- a(1,2,3) =~ ?X.
X = a(1,2,3)
; false.
?- =~(a(1,2,3), ?X, T).
X = a(1,2,3), T = true
; T = false, dif:dif(X,a(1,2,3)).Matches anything, and ignores it.
?- a(1,2,3) =~ (*).
true.
?- =~(a(1,2,3), *, T).
T = true.Matches a compound term, applying patterns recursively. If the compound term is ground,
you can use (+)/1 instead.
?- a(1,2,3,4) =~ \a(+1, -A, ?B, *).
A = 2, B = 3
; false.
?- =~(a(1,2,3,4), \a(+1, -A, ?B, *), T).
A = 2, B = 3, T = true
; A = 2, T = false, dif:dif(B,3).Binds the whole pattern to a variable. It can be used at any nesting level, not just at the top level.
?- a(1,2,3,4) =~ All << \a(+1, -A, ?B, *).
All = a(1,2,3,4), A = 2, B = 3
; false.
?- =~(a(1,2,3,4), All << \a(+1, -A, ?B, *), T).
All = a(1,2,3,4), A = 2, B = 3, T = true
; All = a(1,2,3,4), A = 2, T = false, dif:dif(B,3).Runs a reified predicate after the bindings to decide if the pattern matches.
?- use_module(library(clpz)).
true.
?- a(50) =~ (\a(-N) | clpz_t(N #< 25)).
false.
?- a(10) =~ (\a(-N) | clpz_t(N #< 25)).
N = 10.
?- =~(a(50), (\a(-N) | clpz_t(N #< 25)), T).
N = 50, T = false.
?- =~(a(10), (\a(-N) | clpz_t(N #< 25)), T).
N = 10, T = true.The match/2 predicate implements something like a switch/match statement on top of
if_/3 and the pattern matching predicates from this library. The arms are matched in
order, and the first one to succeed is the one taken.
When a (?)/1 pattern backtracks and tries the dif/2 case, it will test the next
arms in the match/2. The dif/2 constraint will be available for all the arms
from there on.
?- [user].
example_match(Term, Out) :-
match(Term, [
+a ~> Out = 1,
\b(-N) ~> Out = N,
\c(?N) ~> Out = N,
(*) ~> Out = wildcard
]).
?- example_match(a, Out).
Out = 1.
?- example_match(b(10), Out).
Out = 10.
?- example_match(c(10), Out).
Out = 10
; Out = wildcard, dif:dif(_A,10).