Re: Closures in macros

2011-05-08 Thread André Thieme

Am 05.05.2011 02:01, schrieb Ken Wesson:


(There's an ugly workaround
involving explicitly calling intern; you create a dummy namespace with
a var holding the object, and then eval code that refers to that var
by fully-qualified name in order to retrieve the object.)


Yes, this is what I currently do.
In the macro I do
(let [f (gensym "logger")]
  (intern 'my.ns f @*logger*)
  `(~f ~level ...)))

which pollutes the ns of my lib, but for now this works.
Much better would be of course if the core team of Clojure would
implement what you outlined.


Greetings,
André

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Re: Closures in macros

2011-05-08 Thread André Thieme

Hello Ken, thanks for your explanations. It seems that you basically
outlined a strategy that can be used to implement that feature.
Very good! :-)

Am 05.05.2011 02:21, schrieb Ken Wesson:

As for concerns that this kind of extension might mask common macro
errors, adding some *warn-on-foo* option to generate warnings when
"unusual" kinds of object literal were encountered by eval/the
compiler would hopefully address such.


Yes, that’s what I thought too, when I read about Chris Perkins’
concerns. Let the default behaviour be an error message as it now
is, but perhaps a more useful one, and let us have an option in
defmacros attr-map or in a global switch to tell the compiler, or
macroexpander here: “yes, I really want to embed a literal object
in the code”.

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Re: Closures in macros

2011-05-05 Thread Ken Wesson
On Wed, May 4, 2011 at 8:01 PM, Ken Wesson  wrote:
> Note that instantiating the class with 4 gives us an add-4-to function
> instead of the original add-3-to function here. To actually convert
> that particular closure into code that reproduces it, the array of
> constructor arguments needs to be [{} 3]. (I'm not sure what the map
> argument is used for, but it seems to work when left empty, though not
> when omitted entirely.

I did some more experimenting and the map attaches as metadata to the closure:

user=> (def q (.newInstance (first (.getConstructors (.getClass
(fn-maker3 2 1 (into-array Object [{:foo 1} 3 4])))
#'user/q
user=> (q 10)
43
user=> (meta q)
{:foo 1}

There is also a second constructor for a closure that doesn't take a
map. But it comes second in the sequence returned by .getConstructors.
So you can use (second (.getConstructors ...)) with just the closures.

Note that the fn-maker3 above was defined with:

(defn fn-maker3 [x y] (fn [z] (+ (* z x) y)))

and

user=> ((fn-maker3 3 4) 10)
34

so it looks like the order of the constructor arguments can be
rearranged from what you might expect given how the closure was
defined. That wouldn't stop a clever compiler extension knowing the
order needed (as it decided that order in the first place), saving
them into the closure somehow (e.g. as metadata: {:recreate-args [4
3]}), and converting a closure into the code to recreate it (e.g.

`(.newInstance
   (first (.getConstructors (class-for-name ~(.getName (.getClass closure)
   (into-array Object (quote ~(cons (meta closure) (:recreate-args
(meta closure))

seems like it would evaluate to the required code, given the
:recreate-args metadata, and it would preserve the metadata too).

And since a non-closure also has two constructors -- besides the
no-argument one, one accepting just a metadata map -- the above should
in fact work to externalize any function object for reconstruction
later (in any running session that has the function's class available)
as long as the closed-over values (and the metadata) don't contain
anything non-externalizable. In fact, if closure constructors only
assoced the :recreate-args key into the closure's metadata
automatically as an additional final step you could wrap the above in
#=(eval ...) and use it to define print-dup for AFn.

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Re: Closures in macros

2011-05-04 Thread Ken Wesson
On Wed, May 4, 2011 at 8:16 PM, Ken Wesson  wrote:
> Closures, including ones whose arguments can't be known until runtime,
> can easily be slapped with "implements Serializable" if they haven't
> been already. Indeed, an "extends Serializable" on IFn, on top of the
> above compiler modification to externalize anything serializable,
> would suffice to make it possible to eval (and even AOT-compile) code
> containing any embedded function objects, save for closures that have
> closed over non-serializable objects.

One more clarification: *any* object could be eval'd. It would just be
the case that if you tried to AOT compile code that contained (say, in
the output of a macro expansion) a non-serializable, non-print-dupable
object or a closure that had closed over one, the AOT compile would
fail with a NotSerializableException (and the compiler could catch
that and give a more helpful error message pointing to the offending
line of Clojure code, so you could track down what object was making
the AOT compile fail and fix it, either by replacing the literal
object with code to recreate it or by adding a method to print-dup or
slapping a Serializable on one of your Java classes or deftypes or
whatever).

As for concerns that this kind of extension might mask common macro
errors, adding some *warn-on-foo* option to generate warnings when
"unusual" kinds of object literal were encountered by eval/the
compiler would hopefully address such.

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Re: Closures in macros

2011-05-04 Thread Ken Wesson
On Wed, May 4, 2011 at 8:01 PM, Ken Wesson  wrote:
> Note that instantiating the class with 4 gives us an add-4-to function
> instead of the original add-3-to function here. To actually convert
> that particular closure into code that reproduces it, the array of
> constructor arguments needs to be [{} 3]. (I'm not sure what the map
> argument is used for, but it seems to work when left empty, though not
> when omitted entirely. The compiler can always give closure objects
> metadata amounting to the correct [{} 3] or whatever needed to
> recreate the closure object by calling its class's constructor.

Actually, this would require the arguments to be known at compile
time. For (let [x 3] (fn [y] (+ x y))) this is possible, but for a
return value from

(defn adder-maker [n]
  (fn [y] (+ n y)))

it's not.

But what are we really doing here? There are just two situations where
the compiler is being called. One is on-the-fly eval at runtime, and
then the bytecode could just be built with code that works something
along these lines:

makeJavaClassWithNullPublicStaticFieldItUses();
TheNewClass.THE_PUBLIC_STATIC_FIELD = someValue;

Here "someValue" would be an actual reference to the existing object
in memory, and it will work with closures and any other object, even
things like io streams backed by open file handles.

The second is for AOT compilation of Clojure code. In that case, what
we should probably aim for is that a) anything for which print-dup has
a method and b) anything that implements Serializable can be
externalized. For print-dupables you just print-dup to a string and
generate a class whose static initializer puts that back in through
the reader: something like

static {
someVar = RT.readString("(sorted-map [1 2 3 4])");
}

The proof of concept for Serializables is similar:

static {
someVar = (new ObjectInputStream
(new ByteArrayInputStream
(new byte[] {0x1b, 0xff, 0x3a, 0xa7, ...}))).readObject();
}

where the contents of the byte array literal are generated using
ObjectOutputStream/ByteArrayOutputStream, natch.

Closures, including ones whose arguments can't be known until runtime,
can easily be slapped with "implements Serializable" if they haven't
been already. Indeed, an "extends Serializable" on IFn, on top of the
above compiler modification to externalize anything serializable,
would suffice to make it possible to eval (and even AOT-compile) code
containing any embedded function objects, save for closures that have
closed over non-serializable objects.

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Re: Closures in macros

2011-05-04 Thread Ken Wesson
On Wed, May 4, 2011 at 7:03 PM, Simon Katz  wrote:
> It is not possible to write out a function object (something returned
> by lambda, Common Lisp's equivalent of fn) to a compiled file.  No mix
> of eval-when, separating functions and macros, and load order can
> change that.

The same is not true of Clojure functions, though. Any function object
reference can be turned in bytecode into a constructor call to the
appropriate class -- with a closure, passing the appropriate argument.
For example:

user=> (class map)
clojure.core$map
user=> (.newInstance (class map))
#
user=> (.invoke (.newInstance (class map)) inc [1 2 3 4 5])
(2 3 4 5 6)

So, to embed map (not 'map or 'clojure.core/map, but map itself) in
(eval `(~map inc [1 2 3 4 5])) you could generate the bytecode for
this Java:

(new clojure.core$map()).invoke(reference-to-inc-function,
reference-to-1-2-3-4-5-vector);

With a closure, it's slightly more complicated:

user=> (def q (class (let [x 3] (fn [y] (+ x y)
#'user/q
user=> q
user$fn__1501$fn__1502
user=> (.invoke (.newInstance (first (.getConstructors q)) (to-array
[{} 4])) 42)
46

Note that instantiating the class with 4 gives us an add-4-to function
instead of the original add-3-to function here. To actually convert
that particular closure into code that reproduces it, the array of
constructor arguments needs to be [{} 3]. (I'm not sure what the map
argument is used for, but it seems to work when left empty, though not
when omitted entirely. The compiler can always give closure objects
metadata amounting to the correct [{} 3] or whatever needed to
recreate the closure object by calling its class's constructor.

The original problem *can* reappear with one step of regress *if* the
constructor arguments include something the compiler doesn't knows how
to turn into bytecode -- i.e. (eval (atom {})) still won't work, and
so neither will (eval (let [x (atom {})] (fn [y] (reset! x y, but
(eval (let [x 3] (fn [y] (+ x y should work at that point as 3 is
something that can already be turned into bytecode.

Of course, for these trivial examples it's easy enough to turn the
function or closure into a quoted expression that constructs it, such
as (eval '(let [x 3] (fn [y] (+ x y. Where we run into problems is
when we want to embed references to already-existing functions or
other objects that lack global names. (There's an ugly workaround
involving explicitly calling intern; you create a dummy namespace with
a var holding the object, and then eval code that refers to that var
by fully-qualified name in order to retrieve the object.)

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Re: Closures in macros

2011-05-04 Thread Simon Katz
On May 4, 11:31 pm, André Thieme  wrote:
> Am 04.05.2011 14:50, schrieb Simon Katz:
>
> >> For example Common Lisp does support this.
>
> > That's not true, or at least it's only partly true.
>
> > Here's a translation of your example into Common Lisp (I added a use
> > of a# in the macro to avoid compiler optimization making the problem
> > go away):
>
> >    (defun f (x) (lambda () x))
> >    (defparameter foo (f 0))
> >    (defmacro bar () `(let ((a# ,foo)) a#))
> >    (defun call-bar () (bar))
>
> > I can compile this within a Lisp image (not compiling to file), and
> > call call-bar with no problems.
>
> > But if I try to compile to file, compilation fails with the error
> >    Object #  is of type FUNCTION which is not
> > externalizable
>
> You need to wrap it into eval-when or separate functions and macros from
> their use into different files and make sure the right load order is
> used. Then this will work in CL.
>
> Andr

It is not possible to write out a function object (something returned
by lambda, Common Lisp's equivalent of fn) to a compiled file.  No mix
of eval-when, separating functions and macros, and load order can
change that.

Simon

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Re: Closures in macros

2011-05-04 Thread David Nolen
On Wed, May 4, 2011 at 6:31 PM, André Thieme wrote:

> You need to wrap it into eval-when or separate functions and macros from
> their use into different files and make sure the right load order is
> used. Then this will work in CL.


Which are probably some of the reasons Clojure chose not to support the
behavior.

David

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Re: Closures in macros

2011-05-04 Thread André Thieme

Am 04.05.2011 14:50, schrieb Simon Katz:

For example Common Lisp does support this.


That's not true, or at least it's only partly true.

Here's a translation of your example into Common Lisp (I added a use
of a# in the macro to avoid compiler optimization making the problem
go away):

   (defun f (x) (lambda () x))
   (defparameter foo (f 0))
   (defmacro bar () `(let ((a# ,foo)) a#))
   (defun call-bar () (bar))

I can compile this within a Lisp image (not compiling to file), and
call call-bar with no problems.

But if I try to compile to file, compilation fails with the error
   Object #  is of type FUNCTION which is not
externalizable


You need to wrap it into eval-when or separate functions and macros from
their use into different files and make sure the right load order is
used. Then this will work in CL.


André

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Re: Closures in macros

2011-05-04 Thread Marshall T. Vandegrift
Alessio Stalla  writes:

> The key point is that in Lisp "code" does not mean "text" [1]. Code is
> made of data structures - lists, symbols, vectors, numbers, ... - and
> macros are just functions that operate on those data structures.

Hmm, interesting.  One of the things that's drawn me to learning Clojure
is the malleability of "code as data," but I hadn't thought about it as
potentially running that deep before.  Thanks for phrasing that in a way
that clicked for me.

> In other words, valid code is no longer determined by the reader (i.e.
> the parser), but by the compiler and/or the interpreter, that take a
> rich data structure as input. The reader is "only" useful to us humans
> to enter code into the system.

OTOH, the compiler still needs a defined interface.  The data structures
the reader is able to produce seem like a convenient definition for what
data structures the compiler should meaningfully consume.  Obviously the
reader producing structures the compiler can't consume is useless, but
the compiler consuming structures the reader can't produce seems equally
problematic to me.  It seems like code which doesn't have a textual
representation would be much more difficult to reason about.  Without
guaranteeing a mapping from every valid compiler input to text which
causes the reader to directly generate that input, it becomes impossible
to inspect what the compiler is actually consuming.

-Marshall

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Re: Closures in macros

2011-05-04 Thread Jonathan Smith
On May 4, 8:50 am, Simon Katz  wrote:
> > For example Common Lisp does support this.
>
> That's not true, or at least it's only partly true.
>
> Here's a translation of your example into Common Lisp (I added a use
> of a# in the macro to avoid compiler optimization making the problem
> go away):
>
>   (defun f (x) (lambda () x))
>   (defparameter foo (f 0))
>   (defmacro bar () `(let ((a# ,foo)) a#))
>   (defun call-bar () (bar))
>
> I can compile this within a Lisp image (not compiling to file), and
> call call-bar with no problems.
>
> But if I try to compile to file, compilation fails with the error
>   Object # is of type FUNCTION which is not
> externalizable
>
> Common Lisp's notion of externalizable objects (when compiling) is
> defined athttp://www.lispworks.com/documentation/HyperSpec/Body/03_bda.htm.
>
> Regards,
> Simon

Yes.

And actually, it is sort of better to think about (lambda () x) { (fn
[] x), in clojure} as the name of a function. Even though it is also a
list, it is also the name of 'the function that returns x'.

When trying to insert the literal function generated by (lambda () x),
you generate an error, because you can't insert literal functions into
macros, they aren't symbolic... only their names are.

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Re: Closures in macros

2011-05-04 Thread Jonathan Smith
On May 3, 5:22 pm, André Thieme  wrote:
> Am 02.05.2011 23:14, schrieb David Nolen:
>
> > The relevant clojure-dev thread.
> >http://groups.google.com/group/clojure-dev/browse_thread/thread/f4907...
>
> > It's not clear whether the core team and the various contributors are
> > interested in supporting the behavior you want. It's also not clear
> > whether the issue is matter of the difficulty of a good implementation
> > or simply disinterest.
>
> Thanks for that link. I would really like to hear (read) a statement of
> one member of the core team.
> Some of the limitations:
> 1. (defmacro x [] `(let [a# ~(atom 0)]))
>
> 2. (defmacro y [] `(let [a# ~(comp inc inc)])) ; from that link
>
> 3. (defmacro z [] `(let [a# ~((fn [x#] (fn [] x#)) 0)]))
>
> All three calls fail, (x) and (y) and (z).
> I see no plausible reason why it *should* be that way.
> Instead this is useful and idiomatic lisp.
>
> Normally I wanted to write:
> `(~(get @loggers level @logger)
>    ~(get *level-name* level)
>    ~domain ~msg ~e)
>
> The first get will see if for the given level there is a level
> specific log function. If not it will fall back to the default logger
> logger . So, loggers is a mapping from level to closures and
> logger is a closure. Those closures are functions that take 4 args:
> the log level, a domain, a message and an exception.
>
> Now I have to write instead
> (let [l (get @loggers level @logger)
>        f (gensym "logger")]
>    (intern 'mylib.log f l)
>    `(~f ~(get *level-name* level) ~domain ~msg ~e))
>
> which is plain ugly. I need to artificially invent a name, pollute the
> NS of my logging lib and probably create less efficient code, because
> a lookup of my gensymed ~f will be required at runtime.
> Would be great if this could be fixed easily enough to get included in
> a (near) future version.
>
> Regards,
> Andre

You can do this the original way you were trying to do if you change
your closure factory into a 'closure-code-factory'.

Essentially, instead of returning a (fn [x] ...), you want to return
something that's been syntax-quoted (but of the same form). (You could
make this pretty using a macro).

Then you would insert this anonymous lambda wherever you need it, and
call it inline (after binding with let or using apply). There needn't
be any lookup and It shouldn't be any less efficient than what you are
trying to do.

Of course, you should note that the downside to this entire approach
is that to change the logging settings, you have to recompile the
entire program, which could get quite annoying. (Particularly if you
wanted to turn logging on at a breakpoint or something).

It might be better to take the hit on dereferencing, as it would be
more useful, and then also include an option to eliminate all logging
code by flipping a variable.

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Re: Closures in macros

2011-05-04 Thread Alessio Stalla
On 4 Mag, 16:29, "Marshall T. Vandegrift"  wrote:
> André Thieme  writes:
> > Please try this minimal example in your REPL:
> > (defn f [x] (fn [] x)) ; the closure factory
> > (def foo (f 0)) ; a useful instance
> > (defmacro bar [] `(let [a# ~foo]))
> > and then call (bar)
>
> I'm new to Clojure and don't have much experience with Lisps in general,
> but trying to do this seems weird to me.  My understanding is that
> macros are, well, macros -- code which is expanded at compile-time to
> other code.  In which case the interface the macro facility provides
> isn't a set of compiler hooks, but just the ability to factor and
> abstract the same code you could write without the macro facility.  What
> ultimate code-expansion are you trying to achieve?  Perhaps there's a
> different way to do it which works within the confines of pure code
> re-writing.

The key point is that in Lisp "code" does not mean "text" [1]. Code is
made of data structures - lists, symbols, vectors, numbers, ... - and
macros are just functions that operate on those data structures. In
other words, valid code is no longer determined by the reader (i.e.
the parser), but by the compiler and/or the interpreter, that take a
rich data structure as input. The reader is "only" useful to us humans
to enter code into the system.

Alessio

[1] actually this is matter of debate, for example in the Common Lisp
standard "code" is defined with both meanings, but without
complicating things too much, my point is that the canonical form of
the code - the one that is fed to the compiler - is not text.

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Re: Closures in macros

2011-05-04 Thread Armando Blancas
> 3. (defmacro z [] `(let [a# ~((fn [x#] (fn [] x#)) 0)]))
>
> All three calls fail, (x) and (y) and (z).
> I see no plausible reason why it *should* be that way.

As it's been pointed out, the compiler won't re-compile compiled
code.
Those macros work if you don't unquote the expressions:
(defmacro x [] `(let [a# (atom 0)] a#))
(defmacro y [] `(let [a# (comp inc inc)] a#))
(defmacro z [] `(let [a# ((fn [x#] (fn [] x#)) 0)] a#))
user=> @(x)
0
user=> ((y) 1)
3
user=> ((z))
0

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Re: Closures in macros

2011-05-04 Thread Marshall T. Vandegrift
André Thieme  writes:

> Please try this minimal example in your REPL:
> (defn f [x] (fn [] x)) ; the closure factory
> (def foo (f 0)) ; a useful instance
> (defmacro bar [] `(let [a# ~foo]))
> and then call (bar)

I'm new to Clojure and don't have much experience with Lisps in general,
but trying to do this seems weird to me.  My understanding is that
macros are, well, macros -- code which is expanded at compile-time to
other code.  In which case the interface the macro facility provides
isn't a set of compiler hooks, but just the ability to factor and
abstract the same code you could write without the macro facility.  What
ultimate code-expansion are you trying to achieve?  Perhaps there's a
different way to do it which works within the confines of pure code
re-writing.

-Marshall

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Re: Closures in macros

2011-05-04 Thread Simon Katz
> For example Common Lisp does support this.

That's not true, or at least it's only partly true.

Here's a translation of your example into Common Lisp (I added a use
of a# in the macro to avoid compiler optimization making the problem
go away):

  (defun f (x) (lambda () x))
  (defparameter foo (f 0))
  (defmacro bar () `(let ((a# ,foo)) a#))
  (defun call-bar () (bar))

I can compile this within a Lisp image (not compiling to file), and
call call-bar with no problems.

But if I try to compile to file, compilation fails with the error
  Object # is of type FUNCTION which is not
externalizable

Common Lisp's notion of externalizable objects (when compiling) is
defined at http://www.lispworks.com/documentation/HyperSpec/Body/03_bda.htm.

Regards,
Simon

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Re: Closures in macros

2011-05-04 Thread Alessio Stalla
On 4 Mag, 01:34, Chris Perkins  wrote:
> On May 3, 5:22 pm, André Thieme  wrote:
>
> > Some of the limitations:
> > 1. (defmacro x [] `(let [a# ~(atom 0)]))
>
> > 2. (defmacro y [] `(let [a# ~(comp inc inc)])) ; from that link
>
> > 3. (defmacro z [] `(let [a# ~((fn [x#] (fn [] x#)) 0)]))
>
> > All three calls fail, (x) and (y) and (z).
> > I see no plausible reason why it *should* be that way.
>
> I do - because most of the time, embedding an object in code is
> accidental, caused by messing up the quoting and unquoting. I would
> prefer that evaling something that cannot be produced by the reader be
> an error.
>
> I can see that in some cases, having eval pass unexpected types
> through unchanged can be useful, but I think it would be much more
> common for it to result in hard-to-debug errors, especially for
> beginning macro writers.

Code-is-data is the quintessential feature of Lisp. That some code
cannot be produced by the reader is, at most, a limitation of the
reader, not a reason for making that code illegal.  It can, sure, be a
source of errors, but no more than forgetting to quote or unquote a
symbol in a macro expansion already is. Including closures in compiled
classes is not trivial, but still technically doable, and since as
André demonstrated that it's the basis for certain advanced macro
techniques, imho it's a feature that should not be missing from a
powerful, stable, widely used Lisp like Clojure.

Alessio

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Re: Closures in macros

2011-05-03 Thread Chris Perkins
On May 3, 5:22 pm, André Thieme  wrote:
> Some of the limitations:
> 1. (defmacro x [] `(let [a# ~(atom 0)]))
>
> 2. (defmacro y [] `(let [a# ~(comp inc inc)])) ; from that link
>
> 3. (defmacro z [] `(let [a# ~((fn [x#] (fn [] x#)) 0)]))
>
> All three calls fail, (x) and (y) and (z).
> I see no plausible reason why it *should* be that way.

I do - because most of the time, embedding an object in code is
accidental, caused by messing up the quoting and unquoting. I would
prefer that evaling something that cannot be produced by the reader be
an error.

I can see that in some cases, having eval pass unexpected types
through unchanged can be useful, but I think it would be much more
common for it to result in hard-to-debug errors, especially for
beginning macro writers.

- Chris Perkins

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Re: Closures in macros

2011-05-03 Thread André Thieme

Am 02.05.2011 23:14, schrieb David Nolen:


The relevant clojure-dev thread.
http://groups.google.com/group/clojure-dev/browse_thread/thread/f4907ebca8ef6e11

It's not clear whether the core team and the various contributors are
interested in supporting the behavior you want. It's also not clear
whether the issue is matter of the difficulty of a good implementation
or simply disinterest.


Thanks for that link. I would really like to hear (read) a statement of
one member of the core team.
Some of the limitations:
1. (defmacro x [] `(let [a# ~(atom 0)]))

2. (defmacro y [] `(let [a# ~(comp inc inc)])) ; from that link

3. (defmacro z [] `(let [a# ~((fn [x#] (fn [] x#)) 0)]))

All three calls fail, (x) and (y) and (z).
I see no plausible reason why it *should* be that way.
Instead this is useful and idiomatic lisp.

Normally I wanted to write:
`(~(get @loggers level @logger)
  ~(get *level-name* level)
  ~domain ~msg ~e)

The first get will see if for the given “level” there is a level
specific log function. If not it will fall back to the default logger
“logger”. So, “loggers” is a mapping from level to closures and
“logger” is a closure. Those closures are functions that take 4 args:
the log level, a domain, a message and an exception.

Now I have to write instead
(let [l (get @loggers level @logger)
  f (gensym "logger")]
  (intern 'mylib.log f l)
  `(~f ~(get *level-name* level) ~domain ~msg ~e))

which is plain ugly. I need to artificially invent a name, pollute the
NS of my logging lib and probably create less efficient code, because
a lookup of my gensymed ~f will be required at runtime.
Would be great if this could be fixed easily enough to get included in
a (near) future version.


Regards,
André

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Re: Closures in macros

2011-05-02 Thread David Nolen
On Mon, May 2, 2011 at 4:49 PM, André Thieme wrote:

> I am not interested in the answers of religious fanatics who defend any
> behaviour that the current implementation has, even if it obviously
> limits the expressiveness.
>
>
> Regards,
> André
>

The relevant clojure-dev thread.
http://groups.google.com/group/clojure-dev/browse_thread/thread/f4907ebca8ef6e11

It's not clear whether the core team and the various contributors are
interested in supporting the behavior you want. It's also not clear whether
the issue is matter of the difficulty of a good implementation or simply
disinterest.

David

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Re: Closures in macros

2011-05-02 Thread David Nolen
On Mon, May 2, 2011 at 4:49 PM, André Thieme wrote:

> Maybe there are good reasons why closures should not be real first class
> objects, as it is the case in other programming languages that support
> them. If that is the case I would really like to hear it.
>
> I am not interested in the answers of religious fanatics who defend any
> behaviour that the current implementation has, even if it obviously
> limits the expressiveness.
>
>
> Regards,
> André
>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Re: Closures in macros

2011-05-02 Thread André Thieme

Am 02.05.2011 02:26, schrieb Alan:


You can't embed a function in code as a raw function object


Can anyone give explanations why this is so?
I understand that it may sound provocative, but this sounds to me like
a major bug.


- you need to return code that will result in that function. That it
happens to work for non-closure functions is, as I understand it, a
happy (or not?) accident.

The "workaround" is simple enough: don't do it.


This indeed sounds like a workaround. I don’t want to put you into the
corner of the defenders of that current behaviour. So, please don’t take
my comments as personal criticism.

I just think that a functional programming language should support
closures as first class objects everywhere, also in macros. Especially
if that language is called… “Clojure”.
For example Common Lisp does support this.
In his book “Ansi Common Lisp” Paul Graham wrote:
“With macros, closures, and run-time typing, Lisp transcends object-
oriented programming.”

A modern Lisp like Clojure should indeed support closures in macros.



Instead, return code that will be evaluated in the expansion context
and have the effect you want.


The idea about “static logging” is that this is not required.
I can of course dynamically look the current logger up and simply call
(@*logger* lvl msg)

But with static logging this would still result in dynamic code that
can change its behaviour during runtime. What I want instead is to call
the closure.

Maybe there are good reasons why closures should not be real first class
objects, as it is the case in other programming languages that support
them. If that is the case I would really like to hear it.

I am not interested in the answers of religious fanatics who defend any
behaviour that the current implementation has, even if it obviously
limits the expressiveness.


Regards,
André

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Re: Closures in macros

2011-05-01 Thread Alan
On May 1, 4:42 pm, André Thieme  wrote:
> I am currently writing a neat logging lib and want it to support dynamic
> and static logging. When I activate (static-logging!) then the log macro
> (log :warn "message") will check during macro expansion time which log
> level is currently set and decides based on that if code will be
> generated that logs the message or not.
>
> The user can set any log function and for that purpose I offer some
> closure factories, such as make-writer-logger or make-file-logger.
> Two useful writer-loggers are defined as:
> (def out-logger (make-writer-logger *out*))
> (def err-logger (make-writer-logger *err*))
>
> The make-writer-logger returns a closure that takes a level and a
> message and writes this to the given Writer. Now my current logger is
> stored in an atom, for example the default is
> (let [logger (atom out-logger)] …)
> Inside my log macro I want to call @logger, which unfortunately results
> in an Exception:
> “No matching ctor found for class my.logger$make_writer_logger$fn__1588”
>
> Please try this minimal example in your REPL:
> (defn f [x] (fn [] x)) ; the closure factory
> (def foo (f 0)) ; a useful instance
> (defmacro bar [] `(let [a# ~foo]))
> and then call (bar)
>
> As soon f doesn’t return a closure but just a fn, then this Exception
> is not thrown, but instead the code works.
>
> Just from looking at the macro definition I would say it should work for
> any object as long foo is defined.
>
> Is that behaviour a bug? How easy is it to fix it?
> Are there any work-arounds?

You can't embed a function in code as a raw function object - you need
to return code that will result in that function. That it happens to
work for non-closure functions is, as I understand it, a happy (or
not?) accident.

The "workaround" is simple enough: don't do it. Instead, return code
that will be evaluated in the expansion context and have the effect
you want.

user> (defmacro bar [[name] & body] `(let [~name (f 0)] ~@body))
#'user/bar
user> (bar [log] (log))
0

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Closures in macros

2011-05-01 Thread André Thieme

I am currently writing a neat logging lib and want it to support dynamic
and static logging. When I activate (static-logging!) then the log macro
(log :warn "message") will check during macro expansion time which log
level is currently set and decides based on that if code will be
generated that logs the message or not.

The user can set any log function and for that purpose I offer some
closure factories, such as make-writer-logger or make-file-logger.
Two useful writer-loggers are defined as:
(def out-logger (make-writer-logger *out*))
(def err-logger (make-writer-logger *err*))

The make-writer-logger returns a closure that takes a level and a
message and writes this to the given Writer. Now my current logger is
stored in an atom, for example the default is
(let [logger (atom out-logger)] …)
Inside my log macro I want to call @logger, which unfortunately results
in an Exception:
“No matching ctor found for class my.logger$make_writer_logger$fn__1588”

Please try this minimal example in your REPL:
(defn f [x] (fn [] x)) ; the closure factory
(def foo (f 0)) ; a useful instance
(defmacro bar [] `(let [a# ~foo]))
and then call (bar)

As soon f doesn’t return a closure but just a fn, then this Exception
is not thrown, but instead the code works.

Just from looking at the macro definition I would say it should work for
any object as long foo is defined.

Is that behaviour a bug? How easy is it to fix it?
Are there any work-arounds?


Thanks,
André

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en