From: Zaka on
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
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
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

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
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.