Here are some answers to Matthew's and Thomas comments:

First, oops some function symbols in the code for f in my last mail 
got mixed up. The code should be:

(lambda (x)
  (if (eq (car x) 'g) (h (cadr x)) `(f ,x)))

Sorry. Hope that clarifies some of the questions. h is 
called recursively. If there are no rewrite rules for h 
(i.e. with top-level function symbol on the left-hand side = h).
then the code for h will just be 

(lambda (x) `(h ,x))

Matthew writes

> > (defun comp (f lambdaexp)
> >   (if (heuristis-says-compile f)
> >      (compile f lambdaexp)
> >    (setf (symbol-function f) lambdaexp)))
> 
> Something doesn't seem right here.

The argument "lambdaexp" here is of course created as 
(coerce '(lambda (...) ...) 'function).

> > '(lambda (x) (comp f (generate rewrite-rules-of-f)) (f x))
> 
> You need to be more careful about how you write code in emails, so we
> understand exactly what you mean.  Are you sure you mean to quote this
> above expression?

I'm sorry, if the quote caused confusion. I just wanted to
sketch the ideas of the application, why it needs dynamically
changing functions.
I construct the value after the quote, coerce it to function 
and bind it to the initial function value of f. The first call to f
overwrites its own function definition while it runs,
and I admit that could be called a dirty trick.
I would be willing to change that if necessary.
But that does not help with the general problem: function f 
MUST be changed, when the rewrite rules for f change.

Thomas writes:

> How do you do that check? Please do not tell me you stack such checks one 
> onto another to generate essentially a compiled linear search if you add 
> more and more rewrite rules.

No, basically I have implemented pattern matching for
the left hand sides of rewrite rules (like compilers for 
functional languages with pattern matching do). An intermediate
structure of what I call "multi-terms" is used for that
purpose: it overlaps all common parts of left-hand sides of rewrite rules
(actually a multi-term is the real argument to "generate").
This means that for two rewrite rules

f(g(h(x))) => ... and f(g(k(x))) => ...

the code of f will have only one check for a "g".
(For those who know the Isabelle theorem prover:
"multi-terms" are similar to "nets" used in Isabelle.
Isabelle interprets the nets while I compile them to LISP code). 
The tricky part in the code is that matching is
done modulo associativity and commutativy  
(which function symbols are AC is of course subject 
to change too).

> (funcall (symbol-function ...)). As this is machine-generated 
> code anyway, you will not have to type it every time

Typing it is not the point. For debugging purposes
I can just pretty print the current code. 
Replacing all calls to functions with
funcall's to the symbol-value would make it much
harder to read, and I would have to find
all the many places in the code which just call a function
to change them. That wouldn't be much fun on code
that runs without problems since many years and
with many Lisps (Lucid, Allegro, Clisp, Lispworks).


> (defun f (funcall (symbol-value 'f)))

This should be

(defun f (x) (funcall (symbol-value 'f) x))

and your proposal means that one call to (symbol-function 'f)
is replaced by two successive calls to (symbol-function 'f) and
to (symbol-value 'f)?

That's a nice idea, I will consider that. It would avoid 
cluttering the function bodies with funcall's as discussed above, 
and would  leave "generate" as it is. Maybe the performance 
penalty is indeed low, even though the actual code would have to be

(defun f (&rest args) (apply (symbol-value 'f) args))

since the argument number of f is also subject to change.


Gerhard


Reply via email to