Prev: reverse engineering of compiled lisp code
Next: The King is Dead!? Long live... Scala? Clojure?!
From: Zaka on 31 Oct 2009 00:22 Hello all again. I have done the exercise listed further down. The thing is that I first wrote the commented out version (that didn't work). My question is: Why do the second version works and the first one not. Thanks all for your help. ;; Exercise 9 ;; Define a function like apply, but where any number printed out ;; before it returns will be printed, by default, in octal (base 8). ;; (let ((*print-base* 8)) ;; (defun apply* (fn &rest args) ;; (apply fn args))) (defun apply* (fn &rest args) (let ((*print-base* 8)) (apply fn args))) Saludos. Zaka.
From: Paul Donnelly on 31 Oct 2009 02:47 Zaka <shanatorio(a)gmail.com> writes: > Hello all again. > > I have done the exercise listed further down. > > The thing is that I first wrote the commented out version (that didn't > work). > > My question is: Why do the second version works and the first one not. > > Thanks all for your help. > > ;; Exercise 9 > > ;; Define a function like apply, but where any number printed out > ;; before it returns will be printed, by default, in octal (base 8). > > ;; (let ((*print-base* 8)) > ;; (defun apply* (fn &rest args) > ;; (apply fn args))) > > (defun apply* (fn &rest args) > (let ((*print-base* 8)) > (apply fn args))) *PRINT-BASE* returns to its previous value when the LET is exited. So while *PRINT-BASE was 8 when APPLY* was defined in your first try, it was not 8 when it was called. In the second, it's set to 8 each time APPLY* is called.
From: Barry Margolin on 31 Oct 2009 05:00 In article <4aebbb98$0$271$14726298(a)news.sunsite.dk>, Zaka <shanatorio(a)gmail.com> wrote: > Hello all again. > > I have done the exercise listed further down. > > The thing is that I first wrote the commented out version (that didn't > work). > > My question is: Why do the second version works and the first one not. > > Thanks all for your help. > > ;; Exercise 9 > > ;; Define a function like apply, but where any number printed out > ;; before it returns will be printed, by default, in octal (base 8). > > ;; (let ((*print-base* 8)) > ;; (defun apply* (fn &rest args) > ;; (apply fn args))) > > (defun apply* (fn &rest args) > (let ((*print-base* 8)) > (apply fn args))) Closures only close over lexically-scoped variables. *PRINT-BASE* is a special variable, so the binding is dynamically-scoped, and the closure doesn't capture its binding. -- Barry Margolin, barmar(a)alum.mit.edu Arlington, MA *** PLEASE post questions in newsgroups, not directly to me *** *** PLEASE don't copy me on replies, I'll read them in the group ***
From: Vassil Nikolov on 31 Oct 2009 16:03 On Sat, 31 Oct 2009 05:22:46 +0100, Zaka <shanatorio(a)gmail.com> said: > ... > ;; Define a function like apply, but where any number printed out > ;; before it returns will be printed, by default, in octal (base 8). > ;; (let ((*print-base* 8)) > ;; (defun apply* (fn &rest args) > ;; (apply fn args))) It has been explained why the above does not work; if something along these lines should be made to work (though it's hard to imagine a reason why except for the sake of exercise), then a list of the special variables that need to be captured must be supplied and arranged to be inserted into the function definition (because that list cannot be determined automatically), e.g. as below (since a "spoiler" follows, it is "protected" by a few separating lines). 100 99 98 97 96 95 94 93 92 91 90 89 88 87 86 85 84 83 82 81 80 79 78 77 76 75 74 73 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 (funcall-16 #'prin1 (funcall-8 #'print 64)) prints: #o100 #x40 => 64 where (let ((*print-base* 8) (*print-radix* t)) (defun-with-print-base funcall-8 (fn &rest args) (apply #'funcall fn args))) (let ((*print-base* 16) (*print-radix* t)) (defun-with-print-base funcall-16 (fn &rest args) (apply #'funcall fn args))) where (defmacro defun-with-print-base (name lambda-list &body body) `(defun-with-special-bindings ,name ,lambda-list (*print-base* *print-radix*) ,@body)) where (defmacro defun-with-special-bindings (name lambda-list (&rest special-variables) &body body) "Define a function with call-time special bindings matching definition time. When the function is called, the specified special variables will be bound to the same values they had when the function was defined." (multiple-value-bind (decl-doc body) (parse-decl-doc body '()) (let ((capture-vars (mapcar #'(lambda (s) (gensym (string s))) special-variables))) `(let (,@(mapcar #'list capture-vars special-variables)) (defun ,name ,lambda-list ,@decl-doc (let (,@(mapcar #'list special-variables capture-vars)) ,@body)))))) (defun parse-decl-doc (body decl-doc-acc) "Extract a leading [[declaration* | doc-string]] from the rest of a body. Two values are returned, the declaration-and-doc-string part and the rest of the body. The second argument must be supplied as '() to start the parse." (flet ((declarationp (form) (and (consp form) (eql (first form) 'declare)))) (let ((doc-count (count-if #'stringp decl-doc-acc))) (assert (every #'(lambda (x) (or (declarationp x) (stringp x))) decl-doc-acc)) (assert (<= 0 doc-count 1)) (destructuring-bind (&optional head &rest tail) body (if (or (declarationp head) (and (stringp head) (zerop doc-count) (not (endp tail)))) (parse-decl-doc tail (cons head decl-doc-acc)) (values (nreverse decl-doc-acc) body)))))) ---Vassil. -- "Even when the muse is posting on Usenet, Alexander Sergeevich?"
From: Tobias C. Rittweiler on 31 Oct 2009 16:31 Vassil Nikolov <vnikolov(a)pobox.com> writes: > (defmacro defun-with-special-bindings (name lambda-list > (&rest special-variables) > &body body) > "Define a function with call-time special bindings matching definition time. > When the function is called, the specified special variables will be bound to > the same values they had when the function was defined." > (multiple-value-bind (decl-doc body) (parse-decl-doc body '()) > (let ((capture-vars (mapcar #'(lambda (s) (gensym (string s))) > special-variables))) > `(let (,@(mapcar #'list capture-vars special-variables)) > (defun ,name ,lambda-list > ,@decl-doc > (let (,@(mapcar #'list special-variables capture-vars)) > ,@body)))))) > > (defun parse-decl-doc (body decl-doc-acc) > "Extract a leading [[declaration* | doc-string]] from the rest of a body. > Two values are returned, the declaration-and-doc-string part and the rest of > the body. The second argument must be supplied as '() to start the parse." > (flet ((declarationp (form) > (and (consp form) (eql (first form) 'declare)))) > (let ((doc-count (count-if #'stringp decl-doc-acc))) > (assert (every #'(lambda (x) (or (declarationp x) (stringp x))) > decl-doc-acc)) > (assert (<= 0 doc-count 1)) > (destructuring-bind (&optional head &rest tail) body > (if (or (declarationp head) > (and (stringp head) (zerop doc-count) (not (endp tail)))) > (parse-decl-doc tail (cons head decl-doc-acc)) > (values (nreverse decl-doc-acc) body)))))) Your PARSE-DECL-DOC is commonly called PARSE-BODY. In the case above, it's all you needed --- but just in case you'll ever find yourself in need of more advanced declaration frobbery, let me point you to http://common-lisp.net/project/parse-declarations/ which, of course, also comes with a PARSE-BODY function. -T.
|
Next
|
Last
Pages: 1 2 Prev: reverse engineering of compiled lisp code Next: The King is Dead!? Long live... Scala? Clojure?! |