Can you show me how to rewrite functions in lisp?

Consider this javascript:

function addX(n) { return 3 + n; } alert(addX(6)); //alerts 9 eval('var newFunc = ' + addX.toString().replace("3", "5") + ';'); alert(newFunc(10)); //alert 15 

Please ignore the fact that this is a dubious use and methodology, dangerous, inaccessible in a large code base, etc. It allows you to change the function on the fly based on user input. I donโ€™t have it, but I could just as easily.

I hope you can show me how to do this in lisp. I read a lot of textbooks, read a lot about macros, asked a wider question , tried many times, but ended up short.

I want to know how, in lisp, I can change this function at runtime to add 5 instead. Or anything else that the user can enter.

 (define (addX n) (+ 3 n)) 

I'm not looking for currying ! I know I can do this:

 (define addXCurry (lambda (x) (lambda (n) (+ xn)))) (define add5 (addXCurry 5)) (add5 10) 

But this creates a factory function.
I use a simple example because I want to fully understand the difficult path to something simple enough.


Edit Thank you all for your answers. I assume that my big hang around macros (as I understand them) is that I did not see what completely separates the modification from the record. The javascript example is simple - but you can perform more complex rewrites based on user input.

The macros I saw are based on compilation-time (or, as I believe, on a programmer-time). As in C ++, you cannot have a dynamic template parameter - it must be known at compile time.

(It seems) In lisp you cannot fundamentally change the procedure at runtime the way you can in javascript because you lost the source. You can analyze and redefine it, but you cannot iterate over the elements of a list (a list is a function definition), check each element and decide whether to change it or not. The exception, apparently, are examples of Rainer's answer, which are shaky.

+7
lisp common-lisp
source share
4 answers

The tricky part is that Common Lisp (and some other Lisps) gets rid of the source code. Especially when it comes to the compiler. By default, the source code is gone, and everything remains, then this is machine code. How to restore a Lisp source and in what form?

The reason for this: why should CL be required to store the source? It can be fully compiled for machine code or C code and does not have a / EVAL compiler at runtime. A program can work without much of a development environment (without a compiler, etc.). The Common Lisp environment also should not be required in order to be able to "compile" the code with some restored source code.

And itโ€™s generally difficult.

 (let ((n 0) (step 2)) (defun foo () (incf n step))) 

What is the source above and how can you change STEP? The function depends on the lexical binding.

Another complication:

 (defun foo (n) (+ n #.(random 1.0))) 

How to recover it? Each time Lisp reads the source, a random number will be read.

Another complication:

 (setf (symbol-function 'foo) (compute-function)) 

You can set the value of a function using some arbitrary function or a predefined function (for example, SIN). How to restore them if they are compiled for machine code, loaded as machine code, etc.?

If the Common Lisp implementation stores the source code, FUNCTION-LAMBDA-EXPRESSION retrieves it.

There are two ways:

a) Tell Lisp the source code or remember the source.

Indicate the source.

 (let* ((fs (copy-list '(lambda (n) (+ n 3)))) (fc (compile nil fs))) (print (funcall fc 6)) (setf (third (third fs)) 5) (setf fc (compile nil fs)) (funcall fc 6)) 

Extended example:

Write a DEFINE macro that both remembers the source and defines the function.

 (defmacro define (&rest source) `(progn (setf (get ',(first source) :source) (list* 'defun ',source)) (defun ,@source))) 

Displays the source code in the list of character properties in: SOURCE.

Now we can write a function that modifies the source and compiles it:

 (defun modify (fname modifier) (let ((source (get fname :source))) (when source (setf (get fname :source) (funcall modifier source)) (eval (get fname :source)) (compile fname)))) 

Definition example:

 (define addx (n) (+ n 3)) 

Rewrite example:

 (modify 'addx (lambda (source) (setf (third (fourth source)) 6) source)) 

b) Some Common Lisp implementations implement the FUNCTION-LAMBDA-EXPRESSION function (defined in ANSI Common Lisp).

This function returns three values: source as Lisp data, closure-p, and name. This will allow you to change the source, compile it, and set the name to a new function using COMPILE. Sample code is left as an exercise.

Problem: In Common Lisp, the DEFUN macro defines functions. What the macro does behind the scenes (accounting for the IDE, code rewriting, ...) depends on the implementation. Thus, the code returned by the FUNCTION-LAMBDA-EXPRESSION function (if the implementation returns the source code) may look different for each implementation.

This is an example of LispWorks:

 CL-USER 12 > (function-lambda-expression #'addx) (LAMBDA (N) (DECLARE (SYSTEM::SOURCE-LEVEL #<EQ Hash Table{0} 217874D3>)) (DECLARE (LAMBDA-NAME ADDX)) (+ N 3)) NIL ADDX 

So you can manipulate the original expression and modify it.

+15
source share

The exception is examples in Rainer's answer, which are unstable land.

Why? This is a logical conclusion. You cannot rely on a compiler to save the source code, so just save it yourself.

After that, you can work correctly with the function definition (unlike Javascript, where you just hack into a string representation, which is a vivid example of shaky things).

+7
source share

Our procedure code:

 (define add-x-code '(lambda (n) (+ 3 n))) 

Rate it with the function:

 (define add-x (eval add-x-code)) > (add-x 5) 8 

Change it:

 (define add-x-2 (eval (replace 3 7 add-x-code))) > (add-x-2 5) 12 

This is similar to what you did in your JavaScript code. Whether this is a good idea is not what you requested, so I will leave it alone.

(A simple replacement procedure, I whipped :)

 (define (replace xy list) (map (lambda (x.) (if (equal? x. x) y (if (list? x.) (replace xy x.) x.))) list)) 
+3
source share

The way you write your javascript suggests that you are looking for a macro:

 (define-syntax addX (syntax-rules () ((addX a) (+ 3 a)) ((addX ab) (+ ab)))) 

therefore it gives you:

 > (addX 2) 5 > (addX 2 5) 7 

The macro gives you what you want, since it is not a currying factory function and will not rewrite the macro name for you so that you can go along with the changes (although this could be done with something more complex), but it gives you something what you want, which allows you to change the function on the fly.

+1
source share

All Articles