pm.red 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086
  1. module pm; % The PM Pattern Matcher.
  2. % Author: Kevin McIsaac.
  3. % create!-package('(pm pmpatches formgen pattdefn pmintrfc pattperm
  4. % unify),
  5. % '(contrib pm));
  6. remflag('(i),'reserved); % This package uses I as a global index!!
  7. Comment This is a fairly basic set of definitions for Ap, Map and Ar.
  8. It needs some work. The routine Ar is particularly bad;
  9. % Pattern directed application.
  10. symbolic operator ap;
  11. symbolic procedure ap(f,v);
  12. if car v neq 'list then typerr(v,'ap)
  13. else if not genexp f then
  14. if atom f then f . cdr v
  15. else append(f,cdr v)
  16. else
  17. begin scalar nv;
  18. nv := idsort union(findnewvars f,nil);
  19. v := cdr v;
  20. f := sublis(npair(nv, v), f);
  21. if length nv < length v then f := append(f,pnth(v,length nv +1));
  22. return f
  23. end;
  24. symbolic procedure npair(u, v);
  25. % Forms list of pairs from unequal length list. Terminates at end of
  26. % shortest list.
  27. if u and v then (car u . car v) . npair(cdr u, cdr v) else nil;
  28. %Pattern directed MAP
  29. put('map,'psopfn,'map0);
  30. symbolic procedure map0 arg;
  31. if length arg < 2 then nil
  32. else map1(car arg,cadr arg,if length arg >= 3 then caddr arg else 1);
  33. symbolic procedure map1(fn,v,dep);
  34. if dep>0 then car v . for each j in cdr v collect map1(fn,j,dep-1)
  35. else ap(fn,if atom v or car v neq 'list then list('list, v) else v);
  36. put('ar, 'psopfn, 'ar0);
  37. % ARange of ARray statement.
  38. symbolic procedure ar0 arg;
  39. if length arg <= 1 then nil
  40. else ar1(car arg, if length arg >= 2 then cadr arg else 'list);
  41. symbolic procedure ar1(arg,fn);
  42. if fixp arg then ar4(list(list(1,arg,1)),fn)
  43. else if atom arg or car arg neq 'list then typerr(arg,'ar)
  44. else ar4(for each j in cdr arg collect aarg(j), fn);
  45. symbolic procedure aarg(arg);
  46. revlis(
  47. if fixp arg or genp(arg) then list(1, arg, 1)
  48. else if atom arg or car arg neq 'list then typerr(arg,'ar)
  49. else begin scalar l;
  50. arg := cdr arg;
  51. l := length arg;
  52. return if l eq 1 then list(1, car arg, 1)
  53. else if l eq 2 then list(car arg, cadr arg, 1)
  54. else if l eq 3 then list(car arg, cadr arg, caddr arg)
  55. else typerr(arg,"Ar")
  56. end);
  57. symbolic procedure ar4(lst,fn);
  58. begin scalar s, u, v, w;
  59. u := caar lst; v := cadar lst; w := caddar lst; lst := cdr lst;
  60. while u <= v do
  61. << s := append(s,list u);
  62. u := u + w>>;
  63. return if length(lst) eq 0 then
  64. if fn eq 'list then 'list . s
  65. else map1(fn, 'list . s, 1)
  66. else 'list . for each j in cdr map1(list(lst, fn),'list . s, 1)
  67. collect ar4(car j, cdr j);
  68. end;
  69. put('cat, 'psopfn, 'catx);
  70. symbolic procedure catx u;
  71. % Concatenate two lists.
  72. (if not eqcar(x,'list) then typerr(car u,"list")
  73. else if not eqcar(y,'list) then typerr(cadr u,"list")
  74. else 'list . append(cdr x,cdr y))
  75. where x=reval car u, y=reval cadr u;
  76. %Relational operators.
  77. symbolic procedure simpeq(arg);
  78. begin scalar x;
  79. if length arg < 2 then typerr('equal . arg,"relation");
  80. arg := reval('difference . arg);
  81. arg := if numberp arg then reval(arg = 0)
  82. else <<arg := list('equal,arg, 0);
  83. if x := opmtch(arg) then x else arg>>;
  84. return mksq(arg,1)
  85. end;
  86. symbolic procedure simpgt(arg);
  87. begin scalar x;
  88. if length arg < 2 then typerr('greaterp . arg,"relation");
  89. arg := reval('difference . arg);
  90. arg := if numberp arg then reval(arg > 0)
  91. else <<arg := list('greaterp,arg, 0);
  92. if x := opmtch(arg) then x else arg>>;
  93. return mksq(arg,1)
  94. end;
  95. symbolic procedure simpge(arg);
  96. begin scalar x;
  97. if length arg < 2 then typerr('geq . arg,"relation");
  98. arg := reval('difference . arg);
  99. arg := if numberp arg then reval(arg >= 0)
  100. else <<arg := list('geq,arg, 0);
  101. if x := opmtch(arg) then x else arg>>;
  102. return mksq(arg,1)
  103. end;
  104. symbolic procedure simplt(arg);
  105. simpgt(list(cadr arg,car arg));
  106. symbolic procedure simple(arg);
  107. simpge(list(cadr arg,car arg));
  108. put('equal, 'simpfn, 'simpeq);
  109. put('greaterp, 'simpfn, 'simpgt);
  110. put('geq, 'simpfn, 'simpge);
  111. put('lessp, 'simpfn, 'simplt);
  112. put('leq, 'simpfn, 'simple);
  113. endmodule;
  114. module pmpatches; % Patches to make pattern matcher run in REDUCE 3.4.
  115. % Author: Kevin McIsaac.
  116. % Changes by Rainer M .Schoepf
  117. % remflag('(evenp),'opfn);
  118. % remprop('list,'evfn);
  119. % remprop('list,'rtypefn);
  120. % Redefine LISTEVAL so that the arguments are always returned in prefix
  121. % form.
  122. global '(simpcount!* simplimit!*);
  123. symbolic procedure listeval(u,v);
  124. <<if (simpcount!* := simpcount!*+1)>simplimit!*
  125. then <<simpcount!* := 0;
  126. rederr "Simplification recursion too deep">>;
  127. u := if atom u
  128. then listeval(if flagp(u,'share) then eval u
  129. else cadr get(u,'avalue),v)
  130. else car u . for each x in cdr u collect reval1(x,t);
  131. simpcount!* := simpcount!*-1;
  132. u>>;
  133. % Allow EXPR as a keyword in patterns.
  134. % remprop('expr,'stat);
  135. % Make REVAL of an equation return a simplified value.
  136. fluid '(substitution);
  137. symbolic procedure equalreval u;
  138. if null substitution then 'equal . car u . list reval cadr u
  139. else if evalequal(car u,cadr u) then t
  140. else 0;
  141. % Define function to prevent simplification of arguments of symbolic
  142. % operators.
  143. % If the i'th element of `list' is `nil' then the i'th argument of `fn'
  144. % is left unsimplified by simp. If `list' is longer that the argument
  145. % list of `fn' then the extra indicators are ignored. If `list' is
  146. % shorter than the argument list of `fn' then the remaining arguments
  147. % are simplified, eq nosimp(cat,'(nil T nil)) will cause the 1 and third
  148. % arguments of the functions `cat' to be left un simplified.
  149. symbolic procedure nosimp(fn,list);
  150. <<put(fn, 'nosimp, list);>>;
  151. symbolic operator nosimp;
  152. flag('(nosimp), 'noval);
  153. symbolic procedure fnreval(u,v,mode);
  154. % Simplify list u according to list v. If mode is NIL use AEVAL
  155. % else use REVAL.
  156. if null u then nil
  157. else if v eq t then u
  158. else if null v then for each j in u collect reval1(j ,mode)
  159. else ((if car v then car u
  160. else reval1(car u, mode)) . fnreval(cdr u,cdr v,mode));
  161. % Next two routines are changes to module SIMP to add NOSIMP code.
  162. symbolic procedure opfneval u;
  163. lispeval(car u . for each j in
  164. (if flagp(car u,'noval) then cdr u
  165. else fnreval(cdr u,get(car u,'nosimp),t))
  166. collect mkquote j);
  167. global '(ncmp!* subfg!*);
  168. symbolic procedure simpiden u;
  169. % Convert the operator expression U to a standard quotient.
  170. % Note: we must use PREPSQXX and not PREPSQ* here, since the REVOP1
  171. % in SUBS3T uses PREPSQXX, and terms must be consistent to prevent a
  172. % loop in the pattern matcher.
  173. begin scalar bool,fn,x,y,z,n;
  174. fn := car u; u := cdr u;
  175. if x := valuechk(fn,u) then return x;
  176. if not null u and eqcar(car u,'list)
  177. then return mksq(list(fn,aeval car u),1);
  178. % *** Following line added to add nosimp code.
  179. x := fnreval(u, get(fn, 'nosimp),nil);
  180. % x := for each j in cdr u collect aeval j;
  181. u := for each j in x collect
  182. if eqcar(j,'!*sq) then prepsqxx cadr j
  183. else if numberp j then j
  184. else <<bool := t; j>>;
  185. if u and car u=0
  186. and flagp(fn,'odd) and not flagp(fn,'nonzero)
  187. then return nil ./ 1;
  188. u := fn . u;
  189. if flagp(fn,'noncom) then ncmp!* := t;
  190. if null subfg!* then go to c
  191. else if flagp(fn,'linear) and (z := formlnr u) neq u
  192. then return simp z
  193. else if z := opmtch u then return simp z
  194. else if z := get(car u,'opvalfn) then return apply1(z,u);
  195. % else if null bool and (z := domainvalchk(fn,
  196. % for each j in x collect simp j))
  197. % then return z;
  198. c: if flagp(fn,'symmetric) then u := fn . ordn cdr u
  199. else if flagp(fn,'antisymmetric)
  200. then <<if repeats cdr u then return (nil ./ 1)
  201. else if not permp(z:= ordn cdr u,cdr u) then y := t;
  202. % The following patch was contributed by E. Schruefer.
  203. fn := car u . z;
  204. if z neq cdr u and (z := opmtch fn)
  205. then return if y then negsq simp z else simp z;
  206. u := fn>>;
  207. if (flagp(fn,'even) or flagp(fn,'odd))
  208. and x and minusf numr(x := simp car x)
  209. then <<if flagp(fn,'odd) then y := not y;
  210. u := fn . prepsqxx negsq x . cddr u;
  211. if z := opmtch u
  212. then return if y then negsq simp z else simp z>>;
  213. u := mksq(u,1);
  214. return if y then negsq u else u
  215. end;
  216. endmodule;
  217. module formgen; % Form function for !?.
  218. % Author: Kevin McIsaac.
  219. put('!?,'formfn,'formgen)$
  220. symbolic procedure formgen(u,vars,mode);
  221. begin scalar x;
  222. u := cadr u;
  223. if atom u
  224. then if u eq '!?
  225. then <<u := intern '!?!?;
  226. x := list(mkquote u,mkquote 'mgen,t)>>
  227. else <<u := intern compress('!! . '!? . explode u);
  228. x := list(mkquote u,mkquote 'gen,t)>>
  229. else if car u neq '!?
  230. then <<u := intern compress('!! . '!? . explode car u) . cdr u;
  231. x := list(mkquote car u,mkquote 'gen,t)>>
  232. else if car u eq '!? and atom cadr u
  233. then <<u := intern compress('!! . '!? . '!! . '!?
  234. . explode cadr u);
  235. x := list(mkquote u,mkquote 'mgen,t)>>
  236. else
  237. <<u := cadr u;
  238. u := intern compress('!! . '!? . '!! . '!? . explode car u)
  239. . cdr u;
  240. x := list(mkquote car u,mkquote 'gen,t)>>;
  241. return list('progn,'put . x,form1(u,vars,mode))
  242. end;
  243. endmodule;
  244. module pattdefn; %Notational conveniences and low level routines for the
  245. % UNIFY code.
  246. % Author: Kevin McIsaac.
  247. % Changes by Rainer M. Schoepf 1991.
  248. fluid('(freevars op r p i upb
  249. identity expand acontract mcontract comb count symm ))$
  250. % Binding routines. These would be more efficient with a more direct
  251. % mechanism.
  252. symbolic procedure bind(u, v); %push the value of v onto the
  253. put(u,'binding,v.get(u,'binding))$ %binding stack of u
  254. symbolic procedure binding(u); %Top most binding on stack
  255. (lambda x; if x then car x) get(u,'binding)$
  256. symbolic procedure unbind(u); %pop binding off stack
  257. put(u,'binding, cdr get(u,'binding))$
  258. symbolic procedure newenv(u); % Mark a new environment.
  259. bind(u, 'unbound)$ % Give UNIFY lexical scoping.
  260. symbolic procedure restorenv(u); % Should include error checks?
  261. unbind(u)$
  262. symbolic procedure pm!:free(u); % Is u a pm unbound free variable?
  263. binding(u) eq 'unbound$
  264. symbolic procedure bound(u); % Is u a pm bound free variable?
  265. (lambda x; x and (x neq 'unbound)) binding u;
  266. symbolic procedure meq(u,v);
  267. (lambda x;
  268. % (if (x and (x neq 'unbound)) then x else u) eq meval v )
  269. (if (x and (x neq 'unbound)) then x else u) = v)
  270. binding u;
  271. % This has been fixed.
  272. % symbolic procedure meval(u);
  273. % if eqcar(u,'minus) and numberp cadr u then -cadr u else u;
  274. % Currently Mval does nothing. It should be defined so that nosimp
  275. % functions are handled properly. By leaving it out the PM will not
  276. % dynamically change pattern it is working on. I.e.,
  277. % m(f(1,2,3+c),f(?a,?b,?a+?b+?c)) will now return True. If the code
  278. % commented out is restored then this will give the expected result.
  279. % However m(f(1_=natp 1),f(?a_=natp ?a)), where natp(?x) :- t, will not
  280. % work.
  281. symbolic procedure mval(u); u;
  282. %===> if not atom u then (reval bsubs(car u)) . cdr u
  283. %===> else bsubs u;
  284. symbolic procedure bsubs(u);
  285. % Replaces free atoms by their bindings. Would be nice to mark
  286. % expressions that no longer contain bunbound free variables
  287. if null u then u
  288. else if atom u then if bound(u) then binding u else u
  289. else for each j in u collect bsubs j;
  290. symbolic procedure ident(op);
  291. get(op,'identity)$
  292. symbolic procedure genp(u);
  293. atom u and (get(u,'gen) or mgenp(u))$
  294. symbolic procedure mgenp(u);
  295. atom u and get(u,'mgen)$
  296. symbolic procedure suchp u; %Is this a such that condition?
  297. not atom u and car u eq 'such!-that$
  298. % False if any SUCH conditions are in wich all free variable are bound
  299. % does not simplify to T. Should we return free expressions partially
  300. % simplified?
  301. symbolic procedure chk u;
  302. null u or u eq t or
  303. (lambda x;
  304. if freexp(x) then
  305. (lambda y; if null y then nil
  306. else if y eq t then list x
  307. else x.y) chk(cdr u)
  308. else if reval(x) eq t then chk(cdr u) else nil) bsubs car u$
  309. symbolic procedure findnewvars u;
  310. if atom u then if genp u then list u else nil
  311. else for each j in u conc findnewvars j;
  312. symbolic procedure freexp u;
  313. if atom u then pm!:free u else freexp car u or freexp cdr u;
  314. symbolic procedure genexp u;
  315. if atom u then genp u else genexp car u or genexp cdr u;
  316. endmodule;
  317. module pmintrfc; % Interface for pattern matcher.
  318. % Author: Kevin McIsaac.
  319. % Changes by Rainer M. Schoepf 1991.
  320. % For some reason, this doesn't like being compiled as a module.
  321. % REDUCE syntax for pattern matching.
  322. %
  323. % ?a
  324. % This is an ordinary pattern matching variable. It can any value.
  325. %
  326. % ??a
  327. % This is a segment pattern variable. I can take any value as does ?a
  328. % or a set of values.
  329. %
  330. % ?a_=cond
  331. % ?a can only be matched is the condition does not evaluate to false
  332. %
  333. % exp1 -> exp2
  334. % exp1 is replaced by exp2
  335. %
  336. % exp1 --> exp2
  337. % exp1 is replaced by exp2, RHS is quoted. exp2 is simplified after
  338. % replacement
  339. %
  340. % M(exp,pat)
  341. % Returns a list of replacements for pm variables in pat such that pat
  342. % and exp are equal. Where defined the properties of symmetry, assoc-
  343. % iativity and the identity element are used to match the expressions.
  344. %
  345. % S(exp,rep,rpt:1,depth:Inf) or S(exp,{rep1,rep2,...},rpt:1,depth:Inf)
  346. % The lhs of rep is matched against exp and subexpressions of exp.
  347. % When a match is found the replacements for pm variables in rhs are
  348. % substituted into the lhs and the resultant expression is used as a
  349. % replacement. This is done to a maximum (tree) depth of dept, with a
  350. % maximum number of repeats rpt, to a (tree) depth of dept.
  351. % S(exp,rep,depth:Inf) or S(exp,{rep1,rep2,...},depth:Inf)
  352. % Shorthand notation for S with Inf number of rpt's
  353. %
  354. % exp1 :- exp2
  355. % exp1 is added to a global list of automatic replacements. Most
  356. % specific rules are ordered before less specific rules. If a rule
  357. % already exists the the rule is replaced unless exp2 is null in which
  358. % case the rule is deleted.
  359. %
  360. % exp1 ::- exp2
  361. % as above except the RHS is quoted.
  362. %
  363. global '(subfg!*);
  364. fluid '(!*trpm rpt substitution varstack!*);
  365. switch trpm;
  366. put('m,'psopfn,'mx);
  367. symbolic procedure mx u; m1(reval car u,reval cadr u);
  368. symbolic procedure m1(exp, temp);
  369. begin scalar substitution, mmatch, count, freevars;
  370. count := 0;
  371. freevars := idsort union(findnewvars temp,nil);
  372. substitution := if freevars then freevars else t;
  373. for each j in freevars do newenv j;
  374. mmatch := amatch(temp, exp, t, nil);
  375. for each j in freevars do restorenv j;
  376. if mmatch then return
  377. if freevars then 'list . for each j in pair(freevars, mmatch)
  378. collect list('rep, car j, cdr j)
  379. else t
  380. end;
  381. symbolic procedure fixreplist(repset);
  382. % Check that repset is properly formed and add multi-generic
  383. % variables to assoc functions.
  384. begin scalar replist;
  385. if car(repset) memq '(rep repd) then replist := list(repset)
  386. else replist := cdr repset;
  387. replist := for each rep in replist collect fixrep(rep);
  388. return replist
  389. end;
  390. Comment It is necessary to replace all free variables by unique ones
  391. in order to avoid confusion during the superset operation.
  392. To this end we generate replace them by special gensyms
  393. before putting them in the rules database. This is not
  394. visible to the user;
  395. fluid '(pm!:gensym!-count!*);
  396. symbolic (pm!:gensym!-count!* := 0);
  397. symbolic procedure pm!:gensym;
  398. compress ('!? . '!_ .
  399. explode (pm!:gensym!-count!* := pm!:gensym!-count!* + 1));
  400. fluid '(freevarlist!*);
  401. symbolic procedure make!-unique!-freevars form;
  402. if atom form then
  403. if get(form,'gen) then begin scalar x;
  404. x := atsoc (form, freevarlist!*);
  405. if null x then << x := (form . pm!:gensym());
  406. put (cdr x, 'gen, t);
  407. freevarlist!* := x . freevarlist!*>>;
  408. return cdr x
  409. end
  410. else form
  411. else for each x in form collect make!-unique!-freevars x;
  412. symbolic procedure fixrep(repl);
  413. << (repl := make!-unique!-freevars repl) where freevarlist!* := nil;
  414. % Should check if the extra multi-generic variables are required.
  415. if flagp(caadr repl,'assoc) then
  416. if flagp(caadr repl,'symmetric) then
  417. list(car repl,append(cadr repl,list('!?!?!;)),
  418. list(caadr repl,caddr repl,'!?!?!;))
  419. else
  420. list(car repl,caadr(repl) .
  421. ('!?!?!^ . append(cdadr repl,list('!?!?!;))),
  422. list(caadr repl,'!?!?!^,caddr repl,'!?!?!;))
  423. else repl >>;
  424. put('s,'psopfn,'sx);
  425. symbolic procedure sx arg;
  426. % Fill in args for s0. Default: repeat 1, depth Inf.
  427. reval
  428. s0(reval car arg, reval cadr arg,
  429. if cddr arg then reval caddr arg else 1,
  430. if cddr arg and cdddr arg then reval car cdddr arg
  431. else 'inf);
  432. put('si,'psopfn,'si!-x);
  433. symbolic procedure si!-x arg;
  434. % Fill in args for s0. Default: repeat Inf, depth Inf.
  435. reval
  436. s0(reval car arg,reval cadr arg, 'inf,
  437. if cddr arg then reval caddr arg else 'inf);
  438. symbolic procedure s0(exp, repset,rpt,depth);
  439. % Breadth first search. Rpt is passed as a fluid.
  440. if length repset <= 1 or not memq(car repset,'(rep repd list))
  441. then exp
  442. else if (depth neq 'inf and depth < 0)
  443. or (rpt neq 'inf and rpt <=0) or atom(exp) then exp
  444. else sbreadth(exp,fixreplist repset,depth) ;
  445. symbolic procedure sbreadth(exp,replist,depth);
  446. % Substitute a set of replacements into the root expression until
  447. % expression stops changing, then recurse on all the sub expressions.
  448. <<exp:= sroot(exp,replist);
  449. if (depth neq 'inf and depth <= 0)
  450. or (rpt neq 'inf and rpt <=0) or atom(exp) then exp
  451. else ssbreadth(exp,replist,
  452. if depth neq 'inf then depth-1 else depth)>>;
  453. symbolic procedure ssbreadth(exp,replist,depth);
  454. begin scalar newexp, new, reps;
  455. if (depth neq 'inf and depth < 0)
  456. or (rpt neq 'inf and rpt <= 0) or atom(exp) then return exp;
  457. repeat
  458. begin
  459. new := nil;
  460. reps := replist;
  461. a: exp := reval for each subexp in exp collect
  462. << newexp := sroot1(subexp,car reps) ;
  463. new := new or (subexp neq newexp);
  464. newexp
  465. >>;
  466. if not (new or null(reps := cdr reps)) then go to a;
  467. end
  468. until(atom exp or not new);
  469. return
  470. if (depth neq 'inf and depth <= 0)
  471. or (rpt neq 'inf and rpt <= 0) or atom(exp) then exp
  472. else for each subexp in exp collect
  473. ssbreadth(subexp,replist,
  474. if depth neq 'inf then depth-1 else depth)
  475. end;
  476. put('sd,'psopfn,'sdx);
  477. symbolic procedure sdx arg;
  478. % Fill in args for sd0. Default: repeat 1, depth inf.
  479. reval
  480. sd0(reval car arg,reval cadr arg,
  481. if cddr arg then reval caddr arg else 1,
  482. if cddr arg and cdddr arg then reval car cdddr arg
  483. else 'inf);
  484. put('sdi,'psopfn,'sdi);
  485. symbolic procedure sdi arg;
  486. % Fill in args for sd0. Default: repeat Inf, depth Inf.
  487. reval
  488. sd0(reval car arg,reval cadr arg, 'inf,
  489. if cddr arg then reval caddr arg else 'inf);
  490. symbolic procedure sd0(exp, repset,rpt,depth);
  491. % Depth first search.
  492. if length repset <= 1 or not memq(car repset,'(rep repd list))
  493. then exp
  494. else if (depth neq 'inf and depth < 0)
  495. or (rpt neq 'inf and rpt <= 0) or atom(exp) then exp
  496. else sdepth(exp,fixreplist repset,depth) ;
  497. symbolic procedure sdepth(exp,replist,depth);
  498. <<exp:= sroot(exp,replist);
  499. if (depth neq 'inf and depth <= 0)
  500. or (rpt neq 'inf and rpt <= 0) or atom(exp) then exp
  501. else car(exp) . for each subterm in cdr exp collect
  502. sdepth(subterm,replist,
  503. if depth neq 'inf then depth-1 else depth)>>;
  504. symbolic procedure sroot(exp,replist);
  505. % Substitute a set of replacements into a root expression until the
  506. % expression stops changing. When a replacement succeeds the
  507. % substitution process restarts on the new expression at the
  508. % beginning of the replacement list.
  509. begin scalar oldexp, reps;
  510. if (rpt neq 'inf and rpt <=0) or atom(exp) then return exp;
  511. repeat
  512. begin
  513. oldexp := exp;
  514. reps := replist;
  515. a: exp := sroot1(exp,car reps);
  516. if not(exp neq oldexp or null(reps := cdr reps)) then go to a;
  517. if exp neq oldexp then exp := reval exp
  518. end
  519. until(atom exp or exp eq oldexp);
  520. return exp;
  521. end;
  522. symbolic procedure sroot1(exp,rep);
  523. % Try to substitute a single replacement into a root expression once
  524. % only.
  525. begin scalar freevars,substitution,mmatch;
  526. if (rpt neq 'inf and rpt <=0) or
  527. atom(exp) or (car(exp) neq caadr(rep)) then return exp;
  528. freevars := union(findnewvars cadr rep,nil);
  529. substitution := caddr rep;
  530. for each j in freevars do newenv j;
  531. if !*trpm then <<write("Trying rule "); rprint(rep);
  532. write("against "); rprint(exp)>>;
  533. mmatch := amatch(cadr rep, exp, t,nil);
  534. if !*trpm
  535. then <<if mmatch then <<write("producing ");
  536. rprint(mmatch := embed!-null!-fn mmatch)>>
  537. else <<write("failed"); terpri()>>;
  538. terpri()>>;
  539. for each j in freevars do restorenv j;
  540. return if mmatch then
  541. << if (rpt neq 'inf) then rpt := rpt - 1;
  542. embed!-null!-fn mmatch>>
  543. else exp
  544. end;
  545. symbolic procedure embed!-null!-fn u;
  546. if atom u then u
  547. else for each j in u conc
  548. if atom j then list(j)
  549. else if car j eq 'null!-fn then embed!-null!-fn cdr j
  550. else list(embed!-null!-fn j);
  551. algebraic operator null!-fn;
  552. % Code for printing null-fn(a,b,...) as [a,b,...]. Modeled on LIST code.
  553. put('null!-fn,'prifn,'null!-fn!-pri);
  554. fluid '(orig!* posn!*);
  555. symbolic procedure null!-fn!-pri l;
  556. % This definition is basically that of INPRINT, except that it
  557. % decides when to split at the comma by looking at the size of
  558. % the argument.
  559. (begin scalar split,u;
  560. u := l;
  561. l := cdr l;
  562. prin2!* "[";
  563. orig!* := if posn!*<18 then posn!* else orig!*+3;
  564. if null l then go to b;
  565. split := treesizep(l,40); % 40 is arbitrary choice.
  566. a: maprint(negnumberchk car l,0);
  567. l := cdr l;
  568. if null l then go to b;
  569. oprin '!*comma!*;
  570. if split then terpri!* t;
  571. go to a;
  572. b: prin2!* "]";
  573. return u
  574. end)
  575. where orig!* := orig!*;
  576. % Assignments and automatic replacements.
  577. symbolic operator rset;
  578. symbolic procedure rset(temp,exp);
  579. % Add new rule to rule list. If RHS is null then delete rule.
  580. if atom temp then setk(temp,exp)
  581. else begin scalar oldsubfg!*,varstack!*;
  582. %rebind subfg. Don't do this do that(yuck..lisp..)
  583. % rebind varstack!* since the template is simplified again
  584. oldsubfg!* := subfg!*; subfg!* := nil;
  585. temp := reval temp;
  586. put(car temp,'opmtch,
  587. rinsert(fixrep('rset . list(temp,exp)),
  588. get(car temp,'opmtch)));
  589. subfg!* := oldsubfg!*;
  590. return exp
  591. end;
  592. symbolic operator rsetd;
  593. symbolic procedure rsetd(temp,exp);
  594. % Delayed version.
  595. if atom temp then 'hold . setk(temp,exp)
  596. else 'hold . list
  597. begin scalar oldsubfg!*,varstack!*;
  598. %rebind subfg. Don't do this do that(yuck..lisp..)
  599. oldsubfg!* := subfg!*; subfg!* := nil;
  600. temp := reval temp;
  601. put(car temp,'opmtch,
  602. rinsert(fixrep('rsetd . list(temp,exp)),
  603. get(car temp,'opmtch)));
  604. subfg!* := oldsubfg!*;
  605. return exp
  606. end;
  607. symbolic procedure rinsert(rule,rulelist);
  608. % Insert rule in rule list so that most specific rules are found first.
  609. % Use super-set idea, due to Grief. If an equivalent rule exits then
  610. % replace with new rule. A new rule will be placed as far down the rule
  611. % list as possible If the RHS of rule is nil then delete the rule.
  612. if null rulelist or not atom caar rulelist then rule . rulelist
  613. else
  614. (lambda ss;
  615. if ss eq 'equal then
  616. if cadr rule then rule . cdr(rulelist)
  617. else cdr(rulelist)
  618. else if ss eq 't then rule . rulelist
  619. else car(rulelist) . rinsert(rule,cdr rulelist))
  620. superset(cadar rulelist,cadr rule);
  621. symbolic procedure superset(temp1,temp2);
  622. begin scalar mmatch;
  623. mmatch := m1(temp2,temp1);
  624. return(
  625. if null mmatch then nil
  626. else if mmatch eq 't then 'equal
  627. else if not bound2gen(cdr mmatch) then t
  628. else if null (mmatch := m1(temp1,temp1)) then t
  629. else 'equal)
  630. end;
  631. symbolic procedure bound2gen(replist);
  632. % True if all Generic variables are bound to generic variables.
  633. null replist or (genp(caddar replist) and bound2gen(cdr replist));
  634. symbolic operator arep;
  635. symbolic procedure arep(replist);
  636. % Add the replacements in replist to the list of automatically
  637. % applied replacements.
  638. if atom replist then replist
  639. else if car replist eq 'rep
  640. then list('rset ,cadr replist,caddr replist)
  641. else if car replist eq 'repd
  642. then list('rsetd,cadr replist,caddr replist)
  643. else if car replist eq 'list then
  644. % '!*set!* . for each rep in cdr replist collect arep(rep)
  645. 'list . for each rep in cdr replist collect arep(rep)
  646. else nil;
  647. symbolic operator drep;
  648. symbolic procedure drep(replist);
  649. % Delete the replacements in replist from the list of automatically
  650. % applied replacements.
  651. if atom replist then replist
  652. else if car replist eq 'rep then list('rset ,cadr replist,nil)
  653. else if car replist eq 'repd then list('rsetd,cadr replist,nil)
  654. else if car replist eq 'list then
  655. % '!*set!*.for each rep in cdr replist collect Drep(rep)
  656. 'list . for each rep in cdr replist collect drep(rep)
  657. else nil;
  658. symbolic procedure opmtch(exp);
  659. begin scalar oldexp, replist, rpt;
  660. rpt := 'inf;
  661. replist := get(car exp, 'opmtch);
  662. if null(replist) or null subfg!* then return nil;
  663. oldexp := exp;
  664. repeat
  665. exp := if (atom caar replist) then sroot1(exp, car replist)
  666. else oldmtch(exp,car replist)
  667. until (exp neq oldexp or null(replist := cdr replist));
  668. return if exp eq oldexp then nil else exp
  669. end;
  670. symbolic procedure oldmtch(exp,rule);
  671. begin scalar x, y;
  672. y := mcharg(cdr exp, car rule,car exp);
  673. while (y and null x) do
  674. <<x := if eval subla(car y,cdadr rule)
  675. then subla(car y,caddr rule);
  676. y := cdr y>>;
  677. return if x then x else exp
  678. end;
  679. put('!?,'gen,t);
  680. put('!?!?!;,'mgen,t);
  681. put('!?!?!$,'mgen,t);
  682. put('!?!?!^,'mgen,t);
  683. symbolic operator prop!-alg;
  684. newtok '((!_) prop!-alg);
  685. symbolic procedure prop!-alg(f);
  686. begin scalar x;
  687. x := prop f;
  688. while x do <<prin2(car x); prin2(" "); print(cadr x); print(" ");
  689. x := cddr x>>
  690. end;
  691. symbolic operator preceq;
  692. symbolic procedure preceq(u,v);
  693. % Give u same precedence as v.
  694. <<put(u,'op,get(v,'op));
  695. put(u,'infix,get(v,'infix));>>;
  696. newtok '((!: !- ) rset);
  697. newtok '((!: !: !- ) rsetd);
  698. newtok '((!- !>) rep);
  699. newtok '((!- !- !>) repd);
  700. newtok '((!_ !=) such!-that);
  701. flag ('(such!-that), 'spaced); % _ adjacent to symbols causes problems.
  702. algebraic;
  703. infix :-;
  704. nosimp(:-,'(t nil));
  705. %precedence :-,:=; %can't do this
  706. infix ::-;
  707. nosimp(::-,'(t t));
  708. precedence rsetd,rset;
  709. infix ->;
  710. precedence ->,rsetd;
  711. infix -->;
  712. nosimp(-->,'(nil t));
  713. precedence -->,->;
  714. infix _=;
  715. nosimp(_=,'(nil t));
  716. precedence _=,-->;
  717. operator hold;
  718. nosimp(hold,t);
  719. flag('(rset rsetd rep repd such!-that), 'right);
  720. preceq(rsetd,rset);
  721. preceq(-->,->);
  722. flag('(plus times expt),'assoc);
  723. endmodule;
  724. module pattperm; % Rest of unify --- argument permutation, etc.
  725. % Author: Kevin McIsaac.
  726. % When sym!-assoc is off, PM does not force normal generic variables to
  727. % take more than one argument if a multi-generic symbol is present. This
  728. % makes the patterns much more efficient but not fully searched. Sane
  729. % patterns do not require this. For example
  730. % m(a+b+c,?a+??c) will return {?a -> a, ??c -> null!-fn(b,c)} but not
  731. % {?a -> a+b, ??c -> c} or {?a -> a+b+c, ??c -> null!-fn()}
  732. global('(!*sym!-assoc))$
  733. global('(!*udebug))$ %print out next information
  734. symbolic procedure first0(u,n);
  735. if n>0 then car u . first0(cdr u,n-1) else nil;
  736. symbolic procedure last0(u,n);
  737. if n<1 then u else last0(cdr u,n-1);
  738. symbolic procedure list!-mgen u;
  739. % Count the number of top level mgen atoms.
  740. begin integer i;
  741. for each j in u do if atom j and mgenp(j) then i := i+1;
  742. return i
  743. end;
  744. symbolic procedure initarg(u);
  745. begin scalar assoc, mgen, flex, filler; integer n, lmgen;
  746. symm := flagp(op,'symmetric);
  747. n := length(p) - length(r) + 1;
  748. identity := ident(op);
  749. mgen := mgenp(car r);
  750. lmgen := list!-mgen(cdr r);
  751. assoc := flagp(op,'assoc)
  752. and not(symm and(lmgen > 0) and not !*sym!-assoc);
  753. flex := (length(r)>1) and (assoc or lmgen);
  754. filler:= n > 1 or (identity and length p > 0);
  755. %
  756. mcontract := mgen and filler;
  757. acontract := assoc and filler and not mgen;
  758. expand := identity and (n < 1 or flex);
  759. %
  760. i := if flex or n < 1 then
  761. if mgen then 0
  762. else 1
  763. else n;
  764. upb := if identity then length p else n + lmgen;
  765. if symm then comb := initcomb u
  766. end;
  767. symbolic procedure nextarg u;
  768. if symm then s!-nextarg u else o!-nextarg u;
  769. symbolic procedure o!-nextarg u;
  770. begin scalar args;
  771. if !*udebug then uprint(nil);
  772. args :=
  773. if (i = 1) and (i <= upb) then u
  774. else if (i = 0) and (i <= upb) then '(null!-fn).u
  775. else if acontract and (i <= upb)
  776. then mval((op . first0(u,i)) . last0(u,i))
  777. else if mcontract and (i <= upb)
  778. then ('null!-fn . first0(u,i)) . last0(u,i)
  779. else if expand then <<expand := nil; identity . u>>;
  780. i := i + 1;
  781. return args
  782. end;
  783. symbolic procedure s!-nextarg u;
  784. begin scalar v, args;
  785. if !*udebug then uprint(nil);
  786. if null comb then<< i := i + 1; comb := initcomb u>>;
  787. args :=
  788. if (v := getcomb(u,comb) ) then
  789. if (i = 1) and (i <= upb) then caar v . cdr v
  790. else if (i = 0) and (i <= upb) then '(null!-fn).u
  791. else if acontract and (i <= upb) then mval((op.car(v)).cdr v)
  792. else if mcontract and (i <= upb) then ('null!-fn.car(v)).cdr v
  793. else if expand then <<expand := nil; identity . u>>
  794. else nil
  795. else if (i = 0) and (i <= upb) then '(null!-fn).u
  796. else if expand then <<expand := nil; identity.u>>;
  797. return args
  798. end;
  799. symbolic procedure getcomb(u,v);
  800. begin scalar group;
  801. comb := nextcomb(v,i);
  802. group := car comb;
  803. comb := cdr comb;
  804. return if group then group . setdiff(u,group) else nil
  805. end$
  806. symbolic procedure uprint(u);
  807. <<if expand then <<prin2('expand);prin2(" ")>>;
  808. if mcontract then <<prin2('mcontract);prin2(" ")>>;
  809. if acontract then <<prin2('acontract);prin2(" ")>>;
  810. prin2(" upb = ");prin2(upb); prin2(" i = ");prin2(i);
  811. if symm then <<prin2('symmetric);prin2(comb)>>;
  812. terpri()>>$
  813. symbolic procedure initcomb(u); u.nil$
  814. symbolic procedure nextcomb(env,n);
  815. % Env is of the form args . env, where args is a list of arguments.
  816. % Value is list of all combinations of n elements from the list u.
  817. begin scalar args, nenv, v; integer i;
  818. args := car env; nenv := cdr env;
  819. return
  820. if n=0 then nil.nil
  821. else if (i:=length(args) - n)<0 then list(nil)
  822. else if i = 0 then args.nil
  823. else if nenv then <<v := nextcomb(nenv,n - 1);
  824. (car(args) . car(v)) .
  825. (if cdr v then args . cdr v
  826. else list cdr(args))>>
  827. else <<v := nextcomb(initcomb(cdr args),n - 1);
  828. (car(args) . car(v)) . (if cdr v then args . cdr v
  829. else list cdr(args))>>
  830. end;
  831. endmodule;
  832. module unify; % Main part of unify code.
  833. % Author: Kevin McIsaac.
  834. % Changes by Rainer M. Schoepf 1991.
  835. % The switch semantic, default on, controls use of semantic matching.
  836. fluid '(!*semantic substitution);
  837. switch semantic;
  838. !*semantic := t;
  839. symbolic procedure amatch(r,p,suchl,pmstack);
  840. if atom r then unify(nil,mval list r,list p,suchl, pmstack)
  841. else if not(atom p or (car r neq car p)) then
  842. unify(car r,mval cdr r, cdr p, suchl, pmstack)
  843. else if suchp r then amatch(cadr r, p, caddr r . suchl, pmstack)
  844. else if !*semantic then resume(list('equal,r,p).suchl, pmstack);
  845. symbolic procedure suspend(op,r,p,suchl, pmstack);
  846. % Process the interrupting operator.
  847. amatch(car r, car p,suchl,list(op.cdr r,op.cdr p ). pmstack);
  848. symbolic procedure resume(suchl,pmstack);
  849. % Resume interrupted operator.
  850. if pmstack then amatch(caar pmstack,cadar pmstack,suchl,cdr pmstack)
  851. else if chk(suchl) eq t then bsubs substitution;
  852. symbolic procedure unify(op,r,p,suchl,pmstack);
  853. if null r and null p then resume(suchl,pmstack) % Bottom of arg list.
  854. else if null(r) then
  855. <<prin2("UNIFY:pattern over-run for function ");print(op);nil>>
  856. else if null(p) and not (ident(op ) or mgenp(car r)) then
  857. % <<prin2("UNIFY:rule over-run for function ");print(op);NIL>>
  858. nil
  859. else
  860. begin scalar mmatch, st, arg, symm, comb, identity,
  861. mcontract, acontract, expand; integer i, upb;
  862. if pm!:free(car r) then suchl := genp(car r).suchl;
  863. initarg(p);
  864. while (not(mmatch) and (arg := nextarg(p))) do
  865. begin
  866. if not atom(car r)
  867. then mmatch := suspend(op,r,arg,suchl, pmstack)
  868. else if (pm!:free(car r)) then
  869. begin
  870. bind(car r, car arg);
  871. if (st := chk suchl) then
  872. mmatch := unify(op,mval cdr r,cdr arg,st,
  873. pmstack);
  874. unbind(car r);
  875. end
  876. else if meq(car r, car arg)
  877. then mmatch := unify(op,mval cdr r,cdr arg,suchl,
  878. pmstack)
  879. end;
  880. return mmatch
  881. end;
  882. endmodule;
  883. end;