Subject: hints&tips: patterns

From: Tim Menzies <[email-masked]>
Date: Sun, 28 Nov 1999 10:55:25 -0500

i was happy to see jan post the a-a3 trick to this mailing list (see
below).  what i see on this list is lots of sytems stuff (swi-vb interface
etc) but no "neat prolog tricks". and i like neat prolog tricks!

(this is where someone tells me "post that stuff to comp.lang.prolog" and i
reply that "this list is far more active than comp.lang.prolog" also "i
dont want to see general stuff that has prolog-version-specific stuff, i
want to see swi stuff")

anyway, i'm posting the folloing "neat trick", just to see if anyone else
cares to do the same. i would suggest the following ground rules:

** examples must run under swi
** examples must be less than 100 lines long 
   and include demo code and explanation
** copy the following format
** post with subject line "hints&tips: xxx"

--| hints & tips: use of hash_term |-------------------------------
/*author:          Jan Wielemaker <[email-masked]>
  date:            nov 27 1999
  length:          15 lines

Hash-tables are used internally by Prolog to do first-argument indexing
on predicates having lots of clauses.  hash_term/2 is designed to make
it possible to hash on more then just the atomic object or functor of
the first argument.  The idea is that if we want to define a/3, where
argument 1 and 2 should be indexed is replaced by a/4 in this way:
*/
assert_a3(A,B,C) :-
	hash_term(A-B, Hash),
	assert(a(Hash, A, B, C).

a3(A,B,C) :-
	hash_term(A-B, Hash),
	a(Hash, A, B, C).

See also SWI-Prologs :- index(Head). extension.

--| hints & tips: patterns in prolog |-------------------------------
/*author:          Tim Menzies <[email-masked]>
  date:            nov 27 1999
  length:          46 lines

when trying to apply patterns in prolog, i am often faced with the problem
of having a variable principle functor. the following code lets an analyst
define some named pattern
(e.g. the recurse pattern in  pattern/3), including some magic symbol for a
principle functor
(e.g. xxx). then, they can  apply that pattern for multiple instantiations
of xxx (see call to applyPattern/3 at the bottom).

neat things about this example: use of term_expansion/2 to define prolog
macros, use of clause/2 to access prolog's own database of rules, use of
=../2 in swap/3 to recursively descend any term to find certain key symbols
(e.g. xxx), use of maplist in swap/4 to succinctly describe the list
traversal.
*/
% pattern- specified at the analyst level
pattern(recurse, r1(xxx(In),Out)) :- 
	r(In,Temp),
	r(xxx(Temp),Out).

% internal pattern expansion code- invisible to analysts
applyPattern(P,X,Things,Swaps,Out) :-
	bagof(One,P^X^Things^Swaps^
                    applyPattern1(P,X,Things,Swaps,One),
              Out).

applyPattern1(P,X,Things,Swaps,One) :-
	member(X,Things),
	rewrite(P,Swaps,One).

rewrite(P,Swaps,Out):- 
	clause(pattern(P,Head),Body), 
	swap((Head :- Body),Swaps,Out).

swap(X,Swaps,Y)   :- X =.. L0, once(maplist(swap1(Swaps),L0,L1)), Y =.. L1.

swap1(_,H,H)      :- var(H).
swap1(Swaps,H0,H) :- member(H0/H,Swaps).
swap1(_,H,H)      :- atomic(H).
swap1(Swaps,H0,H) :- swap(H0,Swaps,H).

term_expansion((:- usePattern(Pattern,X=Things,Swaps)),
               Out) :-
	applyPattern(Pattern,X,Things,Swaps,Out).

% example of usage: swap all instances of xxx in the recurse pattern with
% head, sum, tail.
:- usePattern(recurse, X=[sum,head,tail], [xxx/X]).

% demo code
demo :- listing(r1).
:- demo.

_____________________________________________________________________
[email-masked]; http://www.tim.menzies.com        PH +1-304-367-8447
NASA, 100 University Dr,Fairmont WV, 26554,USA    FAX +1-304-367-8211
 
If the enemy is in range, so are you. -- Murphy's Law of Combat