Prev: Numbers & Precision
Next: Comparing Lisp to Python, what you consider more important:speed or macros.
From: Krzysztof Drewniak on 3 May 2010 08:43 I am writing a game and would like a hook implementation. I have most of the groundwork but cannot figure out how to actually insert the hook code into a function. Right now, i have a function (hooks object string), which returns the hooks as a form that looks like ((print x) (+ 2 2)) [the actual form is different BTW]. Now, I would like a function (or macro, whatever) (call-hooks object string) so that given the return value of ((print x) (+ 2 2)) from hooks, would make (let ((x 3)) (call-hooks object string)) become (let ((x 3)) (progn (print x) (+ 2 2))) I am really lost on how to implement this. Any help? Krzysztof Drewniak -- X-Real-Email-With-Antispam: krzysdrewniak at gmail dot com pgp key on keyserver.ubuntu.com and maybe some other place too
From: Tamas K Papp on 3 May 2010 09:23 On Mon, 03 May 2010 12:43:47 +0000, Krzysztof Drewniak wrote: > I am writing a game and would like a hook implementation. I have most of > the groundwork but cannot figure out how to actually insert the hook > code into a function. Right now, i have a function (hooks object > string), which returns the hooks as a form that looks like ((print x) (+ > 2 2)) [the actual form is different BTW]. Now, I would like a function > (or macro, whatever) (call-hooks object string) so that given the return > value of ((print x) (+ 2 2)) from hooks, would make > (let ((x 3)) > (call-hooks object string)) > become > (let ((x 3)) > (progn (print x) (+ 2 2))) > I am really lost on how to implement this. Any help? > > Krzysztof Drewniak Would generic functions work for you? Eg (defgeneric call-hooks (object id)) (defmethod call-hooks ((object number) (id (eql 'foo))) (print object) (+ 2 2)) (let ((x 3)) (call-hooks x 'foo)) ; => 4, also prints 3 Note that I use symbols (give faster lookups, bit more lispy) because EQL is not for comparing strings. You can even define a fallback callback (that rolls off the tongue nicely, doesn't it? :-) as (defmethod call-hooks ((object number) id) (print "What should I do with this number?")) (defmethod call-hooks (object id) (print "The most general callback, ever.")) Hope this helps, Tamas
From: Pascal J. Bourguignon on 3 May 2010 11:29 Krzysztof Drewniak <krzysdrewniakNOSPAM(a)gmail.com> writes: > I am writing a game and would like a hook implementation. I have most > of the groundwork but cannot figure out how to actually insert the > hook code into a function. Right now, i have a function > (hooks object string), which returns the hooks as a form that looks > like ((print x) (+ 2 2)) [the actual form is different BTW]. Now, I > would like a function (or macro, whatever) (call-hooks object string) > so that given the return value of ((print x) (+ 2 2)) from hooks, > would make > (let ((x 3)) > (call-hooks object string)) > become > (let ((x 3)) > (progn (print x) (+ 2 2))) > I am really lost on how to implement this. Any help? CLOS already has hooks implemented. They're called :before and :after methods. So if you define a generic function: (defmethod f ((object <some-class>)) ...) you can add a hook: (defmethod f :after ((object <some-class>)) (do-something-after)) (or :before for before). But these would be "programmer-level" hooks. If you want to provide user-level hooks, such as in emacs, then you have to define for each function whether it will have hooks and where (before, in the middle, after, etc). Then you can write: (define-hook *f-before-hook*) (define-hook *f-middle-hook*) (define-hook *f-after-hook*) (defun f (...) (call-hook *f-before-hook* ...) (do-something) (call-hook *f-middle-hook* ...) (do-something-else) (call-hook *f-after-hooks* ...)) (add-hook *f-before-hook* (lambda (...) (print (list before-f ...)))) (add-hook *f-before-hook* (lambda (...) (print "Let's start! Ho!"))) (add-hook *f-after-hook* (lambda (...) (print (list after-f ...)))) (add-hook *f-after-middle* (function my-middle-hook)) (f ...) (defmacro define-hook (name &optional documentation) `(defvar ,name nil ,(or documentation "A hook."))) (defmacro call-hook (hook &rest arguments) (dolist (meat hook) (apply meat arguments))) (defmacro add-hook (hook function) `(push ,function ,hook)) The point is that the meat you put on the hook, won't be a mere sexp or list of sexps, but a full fleshed function. Remember, lisp is a functional programming language, with first class functions, so make good use of them! [Besides, in general (print x) alone doesn't mean anything, because x is not defined; you need a closure to have a variable x to give to print: (lambda (x) (print x)).] -- __Pascal Bourguignon__ http://www.informatimago.com
From: His kennyness on 3 May 2010 11:51 Krzysztof Drewniak wrote: > I am writing a game and would like a hook implementation. I have most > of the groundwork but cannot figure out how to actually insert the > hook code into a function. Right now, i have a function > (hooks object string), <cough> Care to tell us what the string parameter would have been called had you given it a name describing its semantics as opposed to type? ie, is that the selector? > which returns the hooks as a form that looks > like ((print x) (+ 2 2)) [the actual form is different BTW]. Ugh, you mean symbolic form, right? That you want to eval? (But which won't work to capture 'x). Let's have these looks as anonymous first-class functions by runtime, m'kay? > Now, I > would like a function (or macro, whatever) (call-hooks object string) > so that given the return value of ((print x) (+ 2 2)) from hooks, > would make > (let ((x 3)) > (call-hooks object string)) > become > (let ((x 3)) > (progn (print x) (+ 2 2))) > I am really lost on how to implement this. Any help? Ain't happenin. You need your hooks to take parameters and feed the binding of x to the hook. In something more complex such as a game, you will likely pass one parameter that is pretty much the entire universe (so the hooks can do what they like) and a second parameter that will be some object in the universe, such as a player instance. if that sounds too limiting, hooks can take &rest and then as long as you otherwise organize things so you know which kinds of hooks get passed what the caller can do the right thing for each hook. kt
From: Thomas A. Russ on 3 May 2010 12:26 Krzysztof Drewniak <krzysdrewniakNOSPAM(a)gmail.com> writes: > I am writing a game and would like a hook implementation. I have most > of the groundwork but cannot figure out how to actually insert the > hook code into a function. Right now, i have a function > (hooks object string), which returns the hooks as a form that looks > like ((print x) (+ 2 2)) [the actual form is different BTW]. Now, I > would like a function (or macro, whatever) (call-hooks object string) > so that given the return value of ((print x) (+ 2 2)) from hooks, > would make > (let ((x 3)) > (call-hooks object string)) > become > (let ((x 3)) > (progn (print x) (+ 2 2))) > I am really lost on how to implement this. Any help? Well, the real problem you have here is that unless you can do this at macro-expansion time, you won't be able to capture the lexical scope of the variable X. By the very nature and design of lexical arguments, you can't get access to them from something you pass in. The code has to be in the lexical scope of the variable at the time it is compiled. Partly for that reason, one of the standard ways of defining hooks in lisp languages involves making them be functions that you can apply to arguments. That means that you need to know the argument application conventions. But if you are trying to pass the value "by name" as you seem to be doing, you already need to know that X is the name of the variable. So, I would suggest that you follow the standard lisp convention design model of using functions for your hooks. So then your code will look like Hook: (lambda (x) (print x) (+ 2 2)) Invocation: (let ((x 3)) (call-hooks object string x)) Implementation. I assume there can be more than one hook since you named the function CALL-HOOKS instead of CALL-HOOK (defun call-hooks (object string argument) (dolist (f (get-hooks object string)) (funcall f argument))) If there can only be a single one and you want to be able to return a value, then I would do (defun call-hook (object string argument) (let ((f (get-hook object string))) (when f (funcall f argument)))) -- Thomas A. Russ, USC/Information Sciences Institute
|
Next
|
Last
Pages: 1 2 Prev: Numbers & Precision Next: Comparing Lisp to Python, what you consider more important:speed or macros. |