Re: Overlord programs
- From: Pascal Bourguignon <pjb@xxxxxxxxxxxxxxxxx>
- Date: Tue, 31 May 2005 21:46:19 +0200
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.
.
- Follow-Ups:
- Re: Overlord programs
- From: rriggs
- Re: Overlord programs
- References:
- Overlord programs
- From: msas56
- Re: Overlord programs
- From: msas56
- Overlord programs
- Prev by Date: Re: Overlord programs
- Next by Date: Re: capi/cocoa capturing
- Previous by thread: Re: Overlord programs
- Next by thread: Re: Overlord programs
- Index(es):
Relevant Pages
|