<div dir="ltr">sorry the macrolet is not necessary in the foo function<div><br></div><div><div>(defmacro defrule (name args &rest body)</div><div> (let ((foo (gensym))</div><div> (vars (loop for v in args until (eq v :locals) collect v))</div>
<div> (locals (cadr (member :locals args))))</div><div> `(progn</div><div> (ccl::%defun</div><div> (nfunction ,foo</div><div> (LAMBDA ,vars</div><div> (let ,(mapcar #'(lambda (x) `(,x (if (and (var? ,x) (boundp ,x)) (symbol-value ,x) ,x)))</div>
<div> vars)</div><div> (declare (special ,@vars))</div><div> ,@(mapcar #'(lambda (x) `(if (var? ,x) (makunbound ',x))) ; unbound the local variable and not the passed one</div>
<div> vars)</div><div> (with-locals ,locals ; unbound locals and revert back to exact state of locals before running body</div><div> ,@body))))</div>
<div> 'nil)</div><div> (defmacro ,name ,vars</div><div> (list ',foo</div><div> ,@(mapcar #'(lambda (x) ``',,x) vars) ; quote arguments of the function foo to avoid eval </div>
<div> )))))</div></div><div><br></div><div>Regards</div><div>Taoufik</div><div><br></div></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Sun, Dec 29, 2013 at 3:33 PM, Taoufik Dachraoui <span dir="ltr"><<a href="mailto:dachraoui.taoufik@gmail.com" target="_blank">dachraoui.taoufik@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div><div>Hi</div><div><br></div><div>I amanged to define the<span style="white-space:pre-wrap"> </span>macro defrule that do what I want but it<span style="white-space:pre-wrap"> </span>was a difficult process.</div>
<div>The issue is to<span style="white-space:pre-wrap"> </span>manage the special variables ?x,?y,... that are<span style="white-space:pre-wrap"> </span>used by<span style="white-space:pre-wrap"> </span>the select patterns; </div>
<div>if a svar is bound then<span style="white-space:pre-wrap"> </span>the symbol value replaces the svar in the pattern otherwise the<span style="white-space:pre-wrap"> </span>query</div><div>will return all<span style="white-space:pre-wrap"> </span>possible matches<span style="white-space:pre-wrap"> </span>with the svar within the db.</div>
<div class="im">
<div><br></div><div>(defun var? (x)</div><div> (and (symbolp x) (not (keywordp x)) (eq (char (symbol-name x) 0) #\?)))</div><div><br></div></div><div>(defmacro with-locals (locals &rest body)</div><div> (if (null locals)</div>
<div> `(progn ,@body)</div><div> (let ((old-values (gensym)) (dummy (intern (symbol-name (gensym)) :keyword)))</div><div> `(let ((,old-values (mapcar #'(lambda (x) (if (boundp x) (symbol-value x) ,dummy))</div>
<div> ',locals)))</div><div> ,@(mapcar #'(lambda (x) `(makunbound ',x)) locals)</div><div> (let ((r (progn ,@body)))</div><div> (mapcar #'(lambda (x y) (if (not (eq ,dummy y)) (setf (symbol-value x) y))) ',locals ,old-values)</div>
<div class="im">
<div> r)))))</div><div><br></div><div>(defmacro defrule (name args &rest body)</div></div><div> (let ((foo (gensym))</div><div> (vars (loop for v in args until (eq v :locals) collect v))</div><div>
(locals (cadr (member :locals args))))</div>
<div> `(progn</div><div> (ccl::%defun</div><div> (nfunction ,foo</div><div> (LAMBDA ,vars</div><div> (let ,(mapcar #'(lambda (x) `(,x (if (and (var? ,x) (boundp ,x)) (symbol-value ,x) ,x)))</div>
<div> vars)</div><div> (declare (special ,@vars))</div><div> ,@(mapcar #'(lambda (x) `(if (var? ,x) (makunbound ',x))) ; unbound the local variable and not the passed one </div>
<div> vars)</div><div> (with-locals ,locals ; unbound locals and revert back to exact state of locals before running body </div>
<div> (macrolet ((,name ,vars ; within foo the macro name is redirected to call foo recursively </div><div><span style="white-space:pre-wrap"> </span>(list ',foo ,@(mapcar #'(lambda (x) ``',,x) vars))))</div>
<div> ,@body)))))</div><div> 'nil)</div><div> (defmacro ,name ,vars</div><div> (list ',foo</div><div> ,@(mapcar #'(lambda (x) ``',,x) vars) ; quote arguments to function foo to avoid eval </div>
<div> )))))</div></div><div><br></div><div><div>(defrule ancestor (?x ?y :locals (?z))</div><div> (union</div><div> (select-loop (parent ?x ?y) collect `(ancestor ,?x ,?y))</div><div> (select-loop (parent ?x ?z)</div>
<div> append (loop for a in (ancestor ?z ?y) collect `(ancestor ,?x ,(third a)))</div><div> )))</div><div><br></div><div>Example:</div><div><br></div><div>(assert-fact (parent b a))</div><div>(assert-fact (parent c b))</div>
<div>(assert-fact (parent d c))</div><div>(assert-fact (parent e d))</div><div><br></div><div>? (ancestor ?x b)</div><div>((ANCESTOR C B) (ANCESTOR E B) (ANCESTOR D B))</div><div>? (ancestor ?x d)</div><div>((ANCESTOR E D))</div>
<div>? (ancestor c ?x)</div><div>((ANCESTOR C B) (ANCESTOR C A))</div><div>? (ancestor d ?x)</div><div>((ANCESTOR D C) (ANCESTOR D B) (ANCESTOR D A))</div><div>? (ancestor ?x ?y)</div><div>((ANCESTOR B A) (ANCESTOR C B) (ANCESTOR D C) (ANCESTOR E D) (ANCESTOR E C) (ANCESTOR E B) (ANCESTOR E A) (ANCESTOR D B) (ANCESTOR D A) (ANCESTOR C A))</div>
<div><br></div><div><br></div><div>;;; compare this to prolog ;;; (ancestor X Y) :- (parent X Y). </div>
<div>;;; (ancestor X Y) :- (parent X Z),(ancestor Z Y). </div><div><br></div><div> I am planning do the same with another magic macro</div>
<div> the objective is to be able to define a rule such this:</div><div> (defrule ancestor (?x ?y) (or (parent ?x ?y) (and (parent ?x ?z) (ancestor ?z ?y))))</div><div> </div><div>where the disjunctions will be transformed to unions and the conjunctions to nested select-loops;</div>
<div>I am not there yet, it is difficult because of the special variables that I have to manage I am wondering</div><div>if lexicons/dlets of Ron Garret can help here?</div><div><br></div><div>If there is a simpler solution to this I will be happy to hear from you</div>
<div><br></div><div>Kind regards</div></div><span class="HOEnZb"><font color="#888888"><div>Taoufik</div><div><br></div></font></span></div><div class="HOEnZb"><div class="h5"><div class="gmail_extra"><br><br><div class="gmail_quote">
On Sat, Dec 28, 2013 at 10:35 PM, Taoufik Dachraoui <span dir="ltr"><<a href="mailto:dachraoui.taoufik@gmail.com" target="_blank">dachraoui.taoufik@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Hi<div><br></div><div>Thank you for the rapid reply</div><div><br></div><div>the select accepts a pattern with special variables (?x, ?y, ...)</div>
<div><br></div><div>The select when it founds a bound special variable ?x it will replace it by its value in the pattern</div>
<div><br></div><div>Example: with ?x unbound (select-loop (p ?x a) collect it) will return all expressions in the db where the first and the third </div><div>elements are p and a respectively, but if ?x is bound to Z say, then the select will return (p Z a) if it exists in the db</div>
<div><br></div><div>I did this in order to embed queries like the following:</div><div><br></div><div>(select-loop (p ?x a) append (select-loop (?x ?y) collect it) (the second ?x will be bound to the value of ?x returned by the </div>
<div>first select (nested loops)</div><div><br></div><div>I did not see the infinite loop I will check again and see if I can solve this</div><div><br></div><div>Thanks</div><span><font color="#888888"><div>
Taoufik</div><div><br></div></font></span></div><div><div><div class="gmail_extra">
<br><br><div class="gmail_quote">On Sat, Dec 28, 2013 at 10:06 PM, Ron Garret <span dir="ltr"><<a href="mailto:ron@flownet.com" target="_blank">ron@flownet.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
You have an infinite loop in your macroexpansion:<br>
<br>
? (macroexpand-all '(ancestor ?x a))<br>
> Error: Stack overflow on value stack.<br>
<br>
Also, I have no idea what this code is intended to do, but whatever it is this almost certainly isn’t helping:<br>
<br>
? (pprint (macroexpand '(ancestor ?x a)))<br>
<br>
(LET ((?X '?X) (?Y 'A))<br>
(DECLARE (SPECIAL ?X ?Y))<br>
(IF (VAR? ?X) (MAKUNBOUND ?X))<br>
(IF (VAR? ?Y) (MAKUNBOUND ?Y))<br>
(UNION (SELECT-LOOP (P ?X ?Y) COLLECT IT)<br>
(SELECT-LOOP (P ?X ?Z) APPEND (ANCESTOR ?Z ?Y))))<br>
<br>
You are binding ?X to itself, and then immediately making it unbound again. That is almost certainly not what you want to do.<br>
<br>
rg<br>
<div><div><br>
<br>
On Dec 28, 2013, at 12:05 PM, Taoufik Dachraoui <<a href="mailto:dachraoui.taoufik@gmail.com" target="_blank">dachraoui.taoufik@gmail.com</a>> wrote:<br>
<br>
> Hi<br>
><br>
> Could you please check this "Unhandled exception" and explain what is wrong<br>
> with my code<br>
><br>
> (defun var? (x)<br>
> (and (symbolp x) (not (keywordp x)) (eq (char (symbol-name x) 0) #\?)))<br>
><br>
> (defun vars-in (expr)<br>
> (if (atom expr)<br>
> (if (var? expr) (list expr))<br>
> (union<br>
> (vars-in (car expr))<br>
> (vars-in (cdr expr)))))<br>
><br>
> (defmacro aif (test-form then-form &optional else-form)<br>
> `(let ((it ,test-form))<br>
> (if it ,then-form ,else-form)))<br>
><br>
> (defun select! (pat) ; returns a list of bindings<br>
> (print pat)<br>
> '((it . (p b a)) (?x . 'b)))<br>
><br>
> (defmacro select-loop (pat &rest keywords-and-forms)<br>
> (let ((bind (gensym))<br>
> (vars (cons 'it (vars-in pat))))<br>
> `(block select-loop<br>
> (aif (select! ',pat)<br>
> (progn<br>
> (let ((binds it) ,@(mapcar #'list vars))<br>
> (declare (special ,@vars))<br>
> (loop for ,bind in binds<br>
> do (progn<br>
> (setf it (cdr (assoc 'it ,bind)))<br>
> ,@(mapcar #'(lambda (v) `(setf ,v (cdr (assoc ',v ,bind))))<br>
> vars))<br>
> ,@keywords-and-forms)))))))<br>
><br>
> (defmacro defrule (name args &rest body)<br>
> `(defmacro ,name ,args<br>
> (list 'let (list ,@(mapcar #'(lambda (x) `(list ',x `',,x)) args))<br>
> '(declare (special ,@args))<br>
> ,@(mapcar #'(lambda (x) `'(if (var? ,x) (makunbound ,x))) args)<br>
> ,@(mapcar #'(lambda (x) `',x) body))))<br>
><br>
> (defrule ancestor (?x ?y)<br>
> (union<br>
> (select-loop (p ?x ?y) collect it)<br>
> (select-loop (p ?x ?z)<br>
> append (ancestor ?z ?y))))<br>
><br>
> ? (ancestor ?x a)<br>
><br>
> Unhandled exception 10 at 0x28545, context->regs at #xb01641fc<br>
> Exception occurred while executing foreign code<br>
> at compact_dynamic_heap + 965<br>
> received signal 10; faulting address: 0xd360000<br>
> ? for help<br>
> [3422] Clozure CL kernel debugger: ?<br>
> (G) Set specified GPR to new value<br>
> (R) Show raw GPR/SPR register values<br>
> (L) Show Lisp values of tagged registers<br>
> (F) Show FPU registers<br>
> (S) Find and describe symbol matching specified name<br>
> (B) Show backtrace<br>
> (T) Show info about current thread<br>
> (M) Show memory areas<br>
> (X) Exit from this debugger, asserting that any exception was handled<br>
> (P) Propagate the exception to another handler (debugger or OS)<br>
> (K) Kill Clozure CL process<br>
> (V) Show Subversion revision information<br>
> (?) Show this help<br>
> [3422] Clozure CL kernel debugger: B<br>
> current thread: tcr = 0x2000f0, native thread ID = 0xbe03, interrupts enabled<br>
><br>
><br>
> Bogus frame 606b40<br>
> [3422] Clozure CL kernel debugger: L<br>
> [3422] Clozure CL kernel debugger:<br>
><br>
><br>
> Kind regards<br>
> Taoufik<br>
><br>
</div></div>> _______________________________________________<br>
> Openmcl-devel mailing list<br>
> <a href="mailto:Openmcl-devel@clozure.com" target="_blank">Openmcl-devel@clozure.com</a><br>
> <a href="http://clozure.com/mailman/listinfo/openmcl-devel" target="_blank">http://clozure.com/mailman/listinfo/openmcl-devel</a><br>
<br>
</blockquote></div><br></div>
</div></div></blockquote></div><br></div>
</div></div></blockquote></div><br></div>