Re: Overlord programs



msas56@xxxxxxxxx writes:

> Hmmmm maybe that wasn't a very good example because defun will still
> work here. But what if i wanted to modify an existing function , or
> compose a funtion form parts of old functions ? Or what if the Overlord
> program saw the description of a function in an ASCII file and wanted
> to have it as a function of its own ?

DEFUN is useful only if you want to be able to refer to the function by name.
You can build anonymous functions too and refer to them by value (closures).

To manipulate functions as you want, you could keep them in the form of lists.


Some bookkeeping might be done by your implementation, but this is
implementation specific, and most probably you won't be able to count
on it for all functions. For example in clisp you can write:

[139]> (defun zero (x) (lambda (y) (function identity)))
ZERO
[140]> (car (get 'zero 'system::definition))
(DEFUN ZERO (X) (LAMBDA (Y) #'IDENTITY))

But this doesn't work for functions loaded from a .fasl file:

[141]> (with-open-file (src "/tmp/test.lisp" :direction :output
:if-does-not-exist :create :if-exists :supersede)
(print '(defun one (x) (lambda (y) (zero y))) src))
(DEFUN ONE (X) (LAMBDA (Y) (ZERO Y)))
[142]> (load (compile-file "/tmp/test.lisp"))
;; Compiling file /tmp/test.lisp ...
WARNING in ONE in line 2 :
variable X is not used.
Misspelled or missing IGNORE declaration?
;; Wrote file /tmp/test.fas
0 errors, 1 warning
;; Loading file /tmp/test.fas ...
;; Loaded file /tmp/test.fas
T
[143]> (car (get 'one 'system::definition))
NIL
[144]>



So you could use a SYMBOL structure or your own structure to hold
information about functions:

(defstruct funs source function)

(defmacro defuns (name args &body body)
`(defparameter ,name (make-funs :source (quote (lambda ,args ,@body))
:function (lambda ,args ,@body))))

(defuns zero (x) (lambda (y) (function identity)))

[147]> zero
#S(FUNS :SOURCE (LAMBDA (X) (LAMBDA (Y) #'IDENTITY))
:FUNCTION #<FUNCTION :LAMBDA (X) (LAMBDA (Y) #'IDENTITY)>)
[148]>

However this way you have to handle your own function calling:

[148]> (defuns one (x) (lambda (y) (zero y)))

ONE
[149]> one
#S(FUNS :SOURCE (LAMBDA (X) (LAMBDA (Y) (ZERO Y)))
:FUNCTION #<FUNCTION :LAMBDA (X) (LAMBDA (Y) (ZERO Y))>)

Here, one refers to a function ZERO, but we only defined a structure
ZERO, and the function is (funs-function zero) and must be called
with: (funcall (funs-function zero) y)

You may want to do it like this if you're implementing an interpreter
for another language on top of Common Lisp and you don't want to mix
layers.


Rather, if you just want some reflexive features in the Common Lisp
image, just add your own bookkeeping to normal CL stuff, using the
normal SYMBOL structures (the SYMBOL-PLIST accessed with GET):


(defpackage "KEEP-SOURCE-COMMON-LISP"
(:nicknames "KSCL")
(:use "COMMON-LISP")
(:shadow "DEFUN"))
(in-package "KSCL")

(defmacro defun (name args &body body)
`(progn
;; our bookkeeping:
(setf (get ',name :source) '(common-lisp:defun ,name ,args ,@body))
;; COMMON-LISP bookkeeping:
(common-lisp:defun ,name ,args ,@body)))


(defun list-external-symbols (package &key (sorted t))
(let ((pack (find-package package)))
(if pack
(let ((sl '())) (do-external-symbols (s pack) (push s sl))
(if sorted (sort sl (function string<)) sl))
(error "No package ~S" package))))

(export (mapcar (lambda (sym) (intern (string sym) *package*))
(list-external-symbols "COMMON-LISP" :sorted nil)))

(defpackage "KEEP-SOURCE-COMMON-LISP-USER"
(:nicknames "KSCL-USER")
(:use "KEEP-SOURCE-COMMON-LISP"))
(in-package "KSCL-USER")

(defun zero (x) (lambda (y) (function identity)))
(defun one (x) (lambda (y) (zero y)))

(values (get 'zero :source) (get 'one :source))

--> (COMMON-LISP:DEFUN ZERO (X) (LAMBDA (Y) #'IDENTITY)) ;
(COMMON-LISP:DEFUN ONE (X) (LAMBDA (Y) (ZERO Y)))


With this, you can now write your function butchering functions.

(defun both (f1 f2)
(let ((s1 (get f1 :source))
(s2 (get f2 :source)))
(unless (= (length (third s1)) (length (third s2)))
;; TODO: Actually compare the number of arguments, not the length
;; of the argument lists...
(error "Both functions must have the same number of argument."))
(unless (equal (third s1) (third s2))
(error "Substitution of argument names not implemented yet."))
`(defun ,(intern (format nil "BOTH<~A,~A>" f1 f2))
,(third s1)
(values (block ,f1 ,@(cdddr s1))
(block ,f2 ,@(cdddr s2))))))

and you can have some fun:

KSCL-USER[171]> (both 'one 'zero)
(DEFUN |BOTH<ONE,ZERO>| (X)
(VALUES (BLOCK ONE (LAMBDA (Y) (ZERO Y)))
(BLOCK ZERO (LAMBDA (Y) #'IDENTITY))))

KSCL-USER[172]> (eval (both 'one 'zero))
|BOTH<ONE,ZERO>|

KSCL-USER[173]> (|BOTH<ONE,ZERO>| (function one))
#<FUNCTION :LAMBDA (Y) (ZERO Y)> ;
#<FUNCTION :LAMBDA (Y) #'IDENTITY>

KSCL-USER[176]> (get '|BOTH<ONE,ZERO>| :source)
(COMMON-LISP:DEFUN |BOTH<ONE,ZERO>| (X)
(VALUES (BLOCK ONE (LAMBDA (Y) (ZERO Y)))
(BLOCK ZERO (LAMBDA (Y) #'IDENTITY))))


--
__Pascal Bourguignon__ http://www.informatimago.com/
Kitty like plastic.
Confuses for litter box.
Don't leave tarp around.
.



Relevant Pages

  • Re: recursion performance
    ... "function that converts Church numerals to normal ones" ... (defun plus (n m) ... (defun plus* (n m) ... (setq *zero* nil) ...
    (comp.lang.lisp)
  • Re: How to save lists containing functions to disk
    ... For functions defined with DEFUN, you could shadow DEFUN, ... (cl:defmacro defmacro (name args &body body) ... In the case of a single function in a closure, ... gives an API to access the environment, ...
    (comp.lang.lisp)
  • Re: Is anything easier to do in java than in lisp?
    ... > fine as long as I don't care about bringing along their internal state. ... (defun save-function (fun lambda-form) ... (defmacro defun* (name &body body) ...
    (comp.lang.lisp)
  • Re: A "killer" macro
    ... (defun hello-world () ... On-exit is supposed to queue the formto run on scope exit; ... This feature is easily implemented with macros (note that defun is ... (defmacro in-scope (&body body) ...
    (comp.lang.lisp)
  • Problem with Practical Common Lisp + sbcl
    ... (defun next-prime (number) ... ; in: DEFUN PRIMEP ... Does this not work in SBCL? ...
    (comp.lang.lisp)