clbnf.red 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. % ----------------------------------------------------------------------
  2. % $Id: clbnf.red,v 1.8 1999/04/13 13:10:55 sturm Exp $
  3. % ----------------------------------------------------------------------
  4. % Copyright (c) 1995-1999 Andreas Dolzmann and Thomas Sturm
  5. % ----------------------------------------------------------------------
  6. % $Log: clbnf.red,v $
  7. % Revision 1.8 1999/04/13 13:10:55 sturm
  8. % Updated comments for exported procedures.
  9. %
  10. % Revision 1.7 1999/04/01 11:26:47 dolzmann
  11. % Reformatted one procedure.
  12. %
  13. % Revision 1.6 1999/03/22 17:07:12 dolzmann
  14. % Changed copyright information.
  15. % Reformatted comments.
  16. %
  17. % Revision 1.5 1999/03/21 13:34:06 dolzmann
  18. % Corrected comments.
  19. %
  20. % Revision 1.4 1996/10/07 11:45:47 sturm
  21. % Added fluids for CVS and copyright information.
  22. %
  23. % Revision 1.3 1996/07/13 10:53:07 dolzmann
  24. % Added black box implementations cl_bnfsimpl, cl_sacatlp, and cl_sacat.
  25. %
  26. % Revision 1.2 1996/07/07 14:34:19 sturm
  27. % Turned some cl calls into service calls.
  28. %
  29. % Revision 1.1 1996/03/22 10:31:27 sturm
  30. % Moved and split.
  31. %
  32. % ----------------------------------------------------------------------
  33. lisp <<
  34. fluid '(cl_bnf_rcsid!* cl_bnf_copyright!*);
  35. cl_bnf_rcsid!* := "$Id: clbnf.red,v 1.8 1999/04/13 13:10:55 sturm Exp $";
  36. cl_bnf_copyright!* := "(c) 1995-1996 by A. Dolzmann and T. Sturm"
  37. >>;
  38. module clbnf;
  39. % Common logic boolean normal forms. Submodule of [cl]. This module
  40. % provides CNF and DNF computation.
  41. %DS
  42. % <SG-DNF> ::= <GOR> . <SGCL>
  43. % <SGCL> ::= (<SGCONJ>,...)
  44. % <SGCONJ> ::= <GAND> . <SATOTVL>
  45. % <GOR> ::= ['or] | ['and]
  46. % <GAND> ::= ['and] | ['or] "opposite to <GOR>"
  47. % <SATOTVL> ::= (<TRUTH VALUE>) | (<ATOMIC FORMULA>, ...)
  48. procedure cl_dnf(f);
  49. % Common logic disjunctive normal form. [f] is a formula. Returns a
  50. % DNF of [f].
  51. rl_simpl(cl_gdnf(f,'or),nil,-1);
  52. procedure cl_cnf(f);
  53. % Common logic conjunctive normal form. [f] is a formula. Returns a
  54. % CNF of [f].
  55. rl_simpl(cl_gdnf(f,'and),nil,-1);
  56. procedure cl_gdnf(f,gor);
  57. % Common logic generic disjunctive normal form. [f] is a formula;
  58. % [gor] is one of [and], [or]. Returns a G-DNF of [f].
  59. begin scalar strictgdnf,gdnf,svrlsiexpla;
  60. f := rl_simpl(rl_nnf f,nil,-1);
  61. svrlsiexpla := !*rlsiexpla;
  62. !*rlsiexpla := nil;
  63. (strictgdnf := cl_strict!-gdnf(f,gor)) where !*rlbnfsm=nil;
  64. if !*rlbnfsm then
  65. strictgdnf := gor . cl_subsume(rl_argn strictgdnf,gor);
  66. !*rlsiexpla := svrlsiexpla;
  67. gdnf := cl_unstrict(strictgdnf,gor);
  68. return gdnf
  69. end;
  70. procedure cl_strict!-gdnf(f,gor);
  71. % Common logic strict generic disjunctive normal form. [f] is a
  72. % formula; [gor] is one of [and], [or]. Returns a strict g-DNF,
  73. % i.e. a formula upto unary [and]'s and [or]'s, which is in g-DNF.
  74. begin scalar w;
  75. w := cl_mkstrict(rl_simpl(cl_strict!-gdnf1(f,gor),nil,-1),gor);
  76. return rl_bnfsimpl(w,gor)
  77. end;
  78. procedure cl_subsume(gcl,gor);
  79. % Common logic subsume. [gcl] is a generic conjunction list; [gor]
  80. % is one of [and], [or]. Returns a generic conjunction list
  81. % equivalent to [gcl]. Performs simplification by subsumption.
  82. begin scalar w;
  83. if null gcl or null cdr gcl then return gcl;
  84. w := cl_subsume1(gcl,gor);
  85. if car w then <<
  86. cddr w := cl_subsume(cddr w,gor);
  87. return cdr w
  88. >>;
  89. return cl_subsume(cdr w,gor)
  90. end;
  91. procedure cl_subsume1(gcl,gor);
  92. % Common logic subsume 1. [gcl] is a generic conjunction list;
  93. % [gor] is one of [and], [or]. A pair $(c,l)$ is returned, where
  94. % $c$ is [nil] or a list of atomic formulas and $l$ is a generic
  95. % conjunction list. [gcl] is modified. The subsumption relation
  96. % beween [car gcl] and all elements of [cdr gcl] is tested. If $c$
  97. % is nil, [car gcl] was suberflous. $l$ is the modified [gcl] in
  98. % which all superflous conjunctions are deleted. If $c$ is non-nil,
  99. % it is [car gcl] and [car gcl] cannot be dropped. If [cl_setrel]
  100. % is used this requires, that [!*rlsiso] and [!*rlidentify] are on.
  101. begin scalar a,w,x,scgcl,oscgcl;
  102. x := cdar gcl;
  103. oscgcl := gcl;
  104. scgcl := cdr gcl;
  105. while scgcl do <<
  106. a := car scgcl; scgcl := cdr scgcl;
  107. w := if !*rlbnfsm then
  108. rl_subsumption(x,cdr a,gor)
  109. else
  110. cl_setrel(x,cdr a,gor);
  111. if w eq 'keep1 then
  112. cdr oscgcl := scgcl
  113. else if w eq 'keep2 then
  114. x := scgcl := nil
  115. else
  116. oscgcl := cdr oscgcl
  117. >>;
  118. if null x then gcl := cdr gcl;
  119. return x . gcl
  120. end;
  121. procedure cl_setrel(l1,l2,gor);
  122. % Common logic set relation. [l1] and [l2] are list of atomic
  123. % formulas. [gor] is one of [and], [or]. Returns [nil], [keep1], or
  124. % [keep2]. If [l1] is a subset of [l2] [keep1] is returned; if [l2]
  125. % is a subset of [l1] [keep2] is returned otherwise [nil] is
  126. % returned.
  127. begin scalar state,a1,hlp;
  128. while l1 and l2 and car l1 eq car l2 do <<
  129. l1 := cdr l1;
  130. l2 := cdr l2
  131. >>;
  132. if null (l1 and l2) then <<
  133. if null (l1 or l2) then return 'keep1; % both equal.
  134. return l2 and 'keep1 or 'keep2
  135. >>;
  136. state := 'keep1;
  137. if rl_ordatp(car l1,car l2) then <<
  138. hlp := l1; l1 := l2; l2 := hlp;
  139. state := 'keep2
  140. >>;
  141. repeat <<
  142. a1 := car l1; l1 := cdr l1;
  143. l2 := memq(a1,l2);
  144. if null l2 then a1 := l1 := nil
  145. >> until null l1;
  146. return a1 and state
  147. end;
  148. procedure cl_strict!-gdnf1(f,gor);
  149. % Common logic disjunctive normal form in strict representation.
  150. % [f] is a formula containing no first-order operators but $\land$
  151. % and $\lor$; [gor] is one of ['and], ['or]. Returns a strict g-DNF
  152. % of [f], i.e. a g-disjunction of g-conjunctions of atomic formulas
  153. % including unary $\lor$ and $\land$ if necessary.
  154. begin scalar gand,op,subgdnfl,noop,noopgdnf;
  155. gand := if gor eq 'or then 'and else 'or;
  156. op := rl_op f;
  157. if op eq gor then
  158. return rl_mkn(gor,for each subf in rl_argn(f) join
  159. rl_argn(cl_strict!-gdnf(subf,gor)));
  160. if op eq gand then <<
  161. subgdnfl := for each subf in rl_argn(f) collect
  162. cl_strict!-gdnf(subf,gor);
  163. % Switch to noop form.
  164. noop := for each subf in subgdnfl collect
  165. for each gconj in rl_argn subf collect rl_argn gconj;
  166. % Computing the cartesian product of the conjunctive lists is
  167. % now equivalent to an application of the law of
  168. % distributivity, though the result is not flat yet.
  169. noopgdnf := cl_bnf!-cartprod noop;
  170. % Switch back to our normal representation.
  171. return rl_mkn(gor,for each gconj in noopgdnf collect
  172. rl_mkn(gand,for each x in gconj join append(x,nil)))
  173. >>;
  174. if rl_cxp op and not rl_tvalp op then
  175. rederr {"cl_strict!-gdnf: illegal operator",op,"in BNF computation"};
  176. return rl_mkn(gor,{rl_mkn(gand,{f})})
  177. end;
  178. procedure cl_mkstrict(f,gor);
  179. % Common logic make strict. [f] is a g-DNF. Returns a strict g-DNF,
  180. % possibly including one truth value.
  181. begin scalar op,gand;
  182. gand := cl_flip gor;
  183. op := rl_op f;
  184. if not rl_cxp op or rl_tvalp op then
  185. return rl_mkn(gor,{rl_mkn(gand,{f})});
  186. if op eq gand then
  187. return rl_mkn(gor,{f});
  188. if op neq gor then
  189. rederr {"BUG IN cl_mkstrict"};
  190. return rl_mkn(gor,for each subf in rl_argn f collect
  191. if rl_op subf eq gand then subf else rl_mkn(gand,{subf}))
  192. end;
  193. procedure cl_unstrict(sgdnf,gor);
  194. % Common logic unstrict, [sdnf] is a sg-DNF; [gor] is one of [and],
  195. % [or]. Returns a g-DNF.
  196. rl_smkn(gor,for each conj in rl_argn sgdnf collect
  197. % A unary g-and does not have a cddr, ignore it.
  198. if cdr rl_argn conj then conj else car rl_argn conj);
  199. procedure cl_bnf!-cartprod(s);
  200. % Common logic boolean normal form cartesian product. [s] is a list
  201. % $(s_1,...,s_n)$ of lists. Returns $s_1 \times ... \times s_n$ as
  202. % a list of $n$-element lists. The empty set and singletons are
  203. % their own cartesian product.
  204. if null s or null cdr s then s else cl_bnf!-cartprod1 s;
  205. procedure cl_bnf!-cartprod1(s);
  206. % Common logic boolean normal form cartesian product. [s] is a list
  207. % $(s_1,...,s_n)$ of lists with $n \geq 2$. Returns $s_1 \times ...
  208. % \times s_n$ as a list of $n$-element lists.
  209. begin scalar w;
  210. if null cdr s then
  211. return for each m in car s collect {m};
  212. w := cl_bnf!-cartprod1 cdr s;
  213. return for each m in car s join
  214. for each y in w collect m . y
  215. end;
  216. procedure cl_sac(sgdnf,gor);
  217. % Common logic subsumption and cut. [sgdnf] is a sg-DNF; [gor] is
  218. % one of [or], [and]. Returns a sg-DNF equivalent to [sgdnf]. This
  219. % procedures performs simplifications based on order theoretical
  220. % subsumption and cut. There are no possible applications of order
  221. % theoretical subsumption and cut between subformulas of the
  222. % returned sg-DNF.
  223. begin scalar w,gand;
  224. if rl_tvalp car rl_argn car rl_argn sgdnf then return sgdnf;
  225. gand := cl_flip(gor);
  226. % switch to noop form
  227. w := for each x in rl_argn sgdnf collect
  228. rl_argn x;
  229. w := cl_applysac(w,gor);
  230. if w eq 'break then
  231. return rl_mkn(gor,{rl_mkn(gand,{cl_cflip('true,gor eq 'or)})});
  232. w := for each x in w join
  233. if x then
  234. {rl_mkn(gand,x)}
  235. else
  236. nil;
  237. if null w then
  238. return rl_mkn(gor,{rl_mkn(gand,{cl_cflip('true,gor eq 'or)})});
  239. return gor . w
  240. end;
  241. procedure cl_applysac(l,gor);
  242. % Common logic apply subsumption and cut. [l] is a list of lists of
  243. % atomic formulas; [gor] is one of [or], [and]. Returns ['break] or
  244. % a list $k$ of list of atomic formulas. If ['break] is returned
  245. % [l] is as a g-DNF equivalent to ['true] in case of ['gor eq 'or]
  246. % and equivalent to ['false] in case ['gor eq 'and]. The lists are
  247. % considered as generic disjunctive normal forms and are in this
  248. % sense equivalent. There is no possible application of order
  249. % theoretical subsumption or cut between elements of $k$.
  250. begin scalar w,ll,res;
  251. ll := l;
  252. while ll do <<
  253. w := cl_applysac1(car ll,res,gor);
  254. if w eq 'break then <<
  255. ll := nil;
  256. res := 'break
  257. >> else <<
  258. ll := cdr ll;
  259. if car w then
  260. res := cdar w . cdr w
  261. else
  262. res := cdr w
  263. >>
  264. >>;
  265. return res
  266. end;
  267. procedure cl_applysac1(c,l,gor);
  268. % Common logic apply subsumption and cut 1. [c] is a list of atomic
  269. % formulas; [l] is a list of list of atomic formulas; [gor] is one
  270. % of [or], [and]. Returns ['break] or a pair $(c' . \lambda)$. If
  271. % ['break] is returned [l] is as a g-DNF equivalent to ['true] in
  272. % case of ['gor eq 'or] and equivalent to ['false] in case ['gor eq
  273. % 'and]. $c'$ is either [nil] or a pair $(\tau . \gamma)$, where
  274. % $\tau$ is one of [T] and [nil] and $\gamma$ is a list of atomic
  275. % formulas. $\lambda$ is a list of list of atomic formulas. If $c'$
  276. % is [nil] then the conjunction over [c] is implied by a
  277. % conjunction over an element in [l]. If $\tau$ is [T] then
  278. % $\gamma$ is equal to $c$, otherwise $\gamma$ is the result of a
  279. % cut between $c$ and an element of $l$. In all cases there is no
  280. % possible application of subsumption or cut between $\gamma$ and
  281. % an arbitrary element of $\lambda$. [l] is modified.
  282. begin scalar w,flg;
  283. flg:=T;
  284. repeat <<
  285. w := cl_applysac2(c,l,gor);
  286. if w eq 'break then <<
  287. w := '(nil); % leave the loop
  288. flg := 'break
  289. >>;
  290. if car w and null caar w then <<
  291. flg:=nil;
  292. c := cdar w;
  293. l := cdr w
  294. >>;
  295. >> until null car w or caar w;
  296. if flg eq 'break then
  297. return 'break;
  298. if null car w then
  299. return w;
  300. return (flg . cdar w) . cdr w
  301. end;
  302. procedure cl_applysac2(c,l,gor);
  303. % Common logic apply subsumption and cut 1. [c] is a list of atomic
  304. % formulas; [l] is a list of list of atomic formulas; [gor] is one
  305. % of [or], [and]. Returns ['break] or a pair ($c'$ . $\lambda$). If
  306. % ['break] is returned [l] is as a g-DNF equivalent to ['true] in
  307. % case of ['gor eq 'or] and equivalent to ['false] in case ['gor eq
  308. % 'and]. $c'$ is either [nil] or a pair $(\tau . \gamma)$, where
  309. % $\tau$ is one of [T] and [nil] and $\gamma$ is a list of atomic
  310. % formulas. $\lambda$ is a list of list of atomic formulas. If $c'$
  311. % is [nil] then the conjunction over [c] is implied by a
  312. % conjunction over an element in [l]. If $\tau$ is [T] then
  313. % $\gamma$ is equal to $c$, otherwise $\gamma$ is the result of a
  314. % cut between $c$ and an element of $l$. [l] is modified. If
  315. % ['break] is returned then the formula $['gor]([c],\phi)$ is
  316. % equivalent to ['true] in the case ['gor eq 'or] or to ['false] in
  317. % the case ['gor eq 'and].
  318. begin scalar w,ll;
  319. if null l then return ( (T . c) . nil);
  320. ll := l;
  321. while ll and ((w := cl_subandcut(c, car ll,gor)) eq 'keep1) do
  322. ll := cdr ll;
  323. if null w then return 'break;
  324. if null ll then return ((T . c) . nil);
  325. if w eq 'keep2 then return (nil . ll);
  326. if w neq 'failed then % [w] is the result of the cut
  327. % between [c] and [car ll].
  328. return (nil . w) . cdr ll;
  329. % We know, that there is no interaction between [c] and [car ll]
  330. w := cl_applysac2(c,cdr ll,gor);
  331. if w eq 'break then
  332. return 'break;
  333. cdr ll := cdr w;
  334. return car w . ll;
  335. end;
  336. procedure cl_subandcut(l1,l2,gor);
  337. % Common logic subsumption and cut. [l1] and [l2] are sorted lists
  338. % of atomic formulas; [gor] is one of ['or], ['and]. Returns
  339. % ['failed], ['keep1], ['keep2] or a list of atomic formulas. Both
  340. % [l1] and [l2] are considered as conjunctions. ['keep1] is
  341. % returned if [l2] subsumes [l1]; ['keep2] is returned if [l1]
  342. % subsumes [l2]. If a list [l] of atomic formulas is returned then
  343. % [l] is the result of a cut between [l1] and [l2]. Both
  344. % subsumption and cut means order theoretical generalizations of
  345. % the respective notions of the propositional calculus.
  346. begin scalar state,w,x; integer c;
  347. x := l1; % Save one of [l1] and [l2] for computing a cut.
  348. % Determing the maximal common prefix of [l1] and [l2] and its length.
  349. while l1 and l2 and (car l1 equal car l2) do <<
  350. c := c+1;
  351. l1 := cdr l1; l2 := cdr l2
  352. >>;
  353. if null (l1 and l2) then << % on of [l1] and [l2] are empty
  354. if null (l1 or l2) then return 'keep1; % both equal.
  355. % [l1] is a ``subset'' of [l2] or vice versa.
  356. return (l2 and 'keep1) or 'keep2
  357. >>;
  358. % We have [l1 and l2] and [car l1 neq car l2].
  359. state := 'keep1;
  360. w := rl_sacat(car l1,car l2,gor); % [w neq 'keep]
  361. if w eq 'keep2 then <<
  362. state := 'keep2;
  363. % swap [l1] and [l2] upto the first element.
  364. w := cdr l1; l1 := cdr l2; l2 := w
  365. >> else if w eq 'keep1 then <<
  366. l1 := cdr l1; l2 := cdr l2
  367. >> else if w then
  368. return cl_trycut(x,c,w,cdr l1,cdr l2)
  369. else if rl_ordatp(car l1,car l2) then << % [car l1 neq car l2]
  370. state := 'keep2;
  371. w := l1; l1 := l2; l2 := w
  372. >>;
  373. % Now [l1] is ``shorter'' than [l2]; no cuts are possible.
  374. while l1 do <<
  375. w := cl_sacatl(car l1, l2,gor);
  376. l2 := cdr w; w := car w;
  377. l1 := cdr l1;
  378. if w neq 'keep1 then
  379. l1 := nil % Leave the loop.
  380. >>;
  381. if w eq 'keep1 then return state;
  382. return 'failed
  383. end;
  384. procedure cl_trycut(l,c,at,l1,l2);
  385. % Common logic try cut. [l], [l1], and [l2] are lists of atomic
  386. % formulas; [c] is an integer; [at] is an atomic formula or
  387. % ['drop]. Returns ['failed] or a sorted list $\lambda$ of atomic
  388. % formulas. If a cut beween [l1] and [l2] are possible then a list
  389. % of atomic formulas is returned, otherwise [nil] is returned. [l]
  390. % is a list $(a_1,...,a_n)$, [l1] is a list $(c_1,...,c_m)$.
  391. % $lambda$ is a list $(a_1,...,a_c,b,c_1,...,c_m)$, where $b$ is
  392. % the atomic formula [at] if [at] is not [drop], otherwise $b$ is
  393. % ommitted.
  394. begin scalar a;
  395. if null l1 and null l2 then <<
  396. l := for i := 1 : c collect <<
  397. a := car l; l := cdr l; a
  398. >>;
  399. if at eq 'drop then
  400. return sort(l,'rl_ordatp);
  401. return sort(at . l,'rl_ordatp)
  402. >>;
  403. if l1 neq l2 then return 'failed;
  404. % [l1] and [l2] are equal.
  405. for i:=1:c do << l1 := car l . l1; l := cdr l >>;
  406. if at neq 'drop then
  407. l1 := at . l1;
  408. return sort(l1,'rl_ordatp)
  409. end;
  410. procedure cl_sacatl(a,l,gor);
  411. % Common logic subsume and cut atomic formula list. [a] is an
  412. % atomic formula; [l] is a sorted list of atomic formulas; [gor] is
  413. % one of [or], [and]. Returns a pair $(\alpha . \lambda)$ where
  414. % $\alpha$ is a relation, ['keep1], or [nil]; [l] is a possibly
  415. % empty list of atomic formulas. $\alpha$ is [T] if [a] is implied
  416. % by an atomic formula from [l]; if $\alpha$ is [nil] then neither
  417. % [a] is implied by an atomic formula from [l] nor a cut between
  418. % [a] and an atomic formula from [l] is possible, otherwise
  419. % $\alpha$ is the result of such a cut. $\lambda$ is the rest of
  420. % [l] not involved in the computation of $\alpha$.
  421. begin scalar w;
  422. if null l then
  423. return '(nil . nil);
  424. if not rl_sacatlp(a,l) then
  425. return (nil . l);
  426. w := rl_sacat(a,car l,gor);
  427. if not w then
  428. return cl_sacatl(a,cdr l,gor);
  429. if w memq '(keep1 keep) then
  430. return ('keep1 . cdr l);
  431. if w eq 'keep2 then
  432. return (nil . cdr l);
  433. return (w . cdr l) % [w] is a relation or [drop]
  434. end;
  435. procedure cl_bnfsimpl(sgdnf,gor);
  436. % Common logic boolean normal form simplification. [sgdnf] is an
  437. % SG-DNF; [gor] is one of the operators [and], [or]. Returns an
  438. % SG-DNF equivalent to [sgdnf]. Performs simplification of [gcl].
  439. % Accesses switch [rlbnfsac].
  440. if !*rlbnfsac then cl_sac(sgdnf,gor) else sgdnf;
  441. procedure cl_sacatlp(a,l);
  442. % Common logic subsumption and cut atomic formula list predicate.
  443. % [a] is an atomic formula; [l] is a list of atomic formulas.
  444. % Returns [T] a subsumption or cut beween [a] and an element of [l]
  445. % is possible.
  446. T;
  447. procedure cl_sacat(a1,a2,gor);
  448. % Common logic subsumption and cut atomic formula. [a1] and [a2]
  449. % are atomic formulas; [gor] is one of the operators [or], [and].
  450. % Returns [nil], one of the identifiers [keep], [keep1], [keep2],
  451. % [drop], or an atomic formula. The return value [nil] indicates
  452. % that neither a cut nor a subsumption can be applied. If [keep] is
  453. % returned, then the atomic formulas are identical. In the case of
  454. % [keep1] or [keep2] the corresponding atomic formula can be kept,
  455. % and the other one can be dropped. If an atomic formula $a$ is
  456. % returned, then this atomic formula is the result of the cut
  457. % beween [a1] and [a2]. If [drop] is returned, then a cut with
  458. % result [true] or [false] can be performed.
  459. if a1 = a2 then 'keep else nil;
  460. endmodule; % [clbnf]
  461. end;