Suggestions & questions

1 view
Skip to first unread message

Frantisek Sodomka

unread,
Aug 5, 2008, 5:11:38 PM8/5/08
to clo...@googlegroups.com
Hello!
I would like to suggest extending the number of parameters '=' and 'not='
take, because sometimes it's useful to compare more than 2 values. It
already works for '<' and others:

user=> (< 1 2 3 4)
true
user=> (>= 3 2 1)
true


Also, I am little bit confused about this behavior:

user=> (and true false)
false
user=> (apply and '(true false))
(clojure/let [and__175 true] (if and__175 (clojure/and false) and__175))

; doesnt return false, but expanded form

user=> (if (apply and '(true false)) :true :false)
:true

; this is always true, since form isn't nil or false

user=> (map and '(true false) '(false true))
((clojure/let [and__175 true] (if and__175 (clojure/and false) and__175))
(clojure/let [and__175 false] (if and__175 (clojure/and true) and__175)))

; forms again - not list of '(false false)

Is this expected behaviour? Or a bug?

Thank you for answering, Frantisek

J. McConnell

unread,
Aug 5, 2008, 6:54:56 PM8/5/08
to clo...@googlegroups.com
> Also, I am little bit confused about this behavior:
>
> user=> (and true false)
> false
> user=> (apply and '(true false))
> (clojure/let [and__175 true] (if and__175 (clojure/and false) and__175))

"and" is a macro, not a function. It must be a macro because it has
to control the evaluation of it's arguments, so that any arguments
following an argument evaluating to "false" or "nil" are not evaluated
themselves, which is how the "&&" operator works in most languages.
The result is that the (and ...) expression will be expanded before
being passed to "apply".

HTH,

- J.

Frantisek Sodomka

unread,
Aug 6, 2008, 2:10:56 AM8/6/08
to clo...@googlegroups.com
I understand that "and" needs to be a macro. Try this one though:

(defmacro and2
([] true)
([x] x)
([x & rest]
(eval `(let [and# ~x]
(if and# (and ~@rest) and#)))))

user=> (apply and2 '(true false))
false
user=> (if (apply and2 '(true false)) :true :false)
:false
user=> (map and2 '(true false) '(false true))
(false false)

I am not sure if one parameter calling - ([x] x) - needs to be changed
also.

Frantisek

Frantisek Sodomka

unread,
Aug 6, 2008, 2:27:06 AM8/6/08
to clo...@googlegroups.com
Or should I say:

(defmacro and2
([] true)
([x] x)
([x & rest]
(eval `(let [and# ~x]
(if and# (and2 ~@rest) and#)))))

Similar situation will apply to "or" too. I think it needs to tested more
extensively to see where we are.

Rich Hickey

unread,
Aug 6, 2008, 10:41:54 AM8/6/08
to Clojure


On Aug 6, 2:10 am, "Frantisek Sodomka" <fa...@intricatevisions.com>
wrote:
> I understand that "and" needs to be a macro. Try this one though:
>

> user=> (apply and2 '(true false))

You shouldn't be applying macros. They are meant to be called by the
compiler. The fact that they are implemented as functions is an
implementation detail.

It has been requested that I make such usage an error in an effort to
prevent such mistakes, and I have done so.

Here's the new behavior.

(apply and '(true false))
-> java.lang.Exception: Can't take value of a macro: #'clojure/and

Rich

Frantisek Sodomka

unread,
Aug 6, 2008, 3:18:20 PM8/6/08
to clo...@googlegroups.com
If I understand it right, macros expand at compile time and 'apply' and
'map' work at runtime. Therefore I was mixing compile time with the
runtime, right?

Any comments on extending the number of parameters of '=' and 'not='?

Thank you, Frantisek


On Wed, 06 Aug 2008 16:41:54 +0200, Rich Hickey <richh...@gmail.com>
wrote:

Graham Fawcett

unread,
Aug 6, 2008, 4:16:53 PM8/6/08
to clo...@googlegroups.com
On Wed, Aug 6, 2008 at 3:18 PM, Frantisek Sodomka
<fa...@intricatevisions.com> wrote:

> Any comments on extending the number of parameters of '=' and 'not='?

Yes, I agree that would be a good Lisp-ish design.

You could also write your own, perhaps like this:

(defn all-eq
([] true)
([n] true)
([x & rest] (every? #(= x %) rest)))

Graham

Rich Hickey

unread,
Aug 6, 2008, 4:36:43 PM8/6/08
to Clojure


On Aug 6, 4:16 pm, "Graham Fawcett" <graham.fawc...@gmail.com> wrote:
> On Wed, Aug 6, 2008 at 3:18 PM, Frantisek Sodomka
>
> <fa...@intricatevisions.com> wrote:
> > Any comments on extending the number of parameters of '=' and 'not='?
>
> Yes, I agree that would be a good Lisp-ish design.
>

I've added unary and n-ary support for = and not=, and a new function,
none=.

Rich

Frantisek Sodomka

unread,
Aug 6, 2008, 4:55:12 PM8/6/08
to clo...@googlegroups.com
Happy, happy, happy ;-)

What surprised me is not= and line:
(not (apply = x y more))

Testing:
user=> (apply = 1 1 '(1 1))
true
user=> (apply = 1 1 '(1 2))
false

Interesting behavior of 'apply' with mixed parameters ;-)


On Wed, 06 Aug 2008 22:36:43 +0200, Rich Hickey <richh...@gmail.com>
wrote:
>

Meikel Brandmeyer

unread,
Aug 6, 2008, 5:43:07 PM8/6/08
to clo...@googlegroups.com
Hello,

Am 06.08.2008 um 22:55 schrieb Frantisek Sodomka:
> Testing:
> user=> (apply = 1 1 '(1 1))
> true
> user=> (apply = 1 1 '(1 2))
> false
>
> Interesting behavior of 'apply' with mixed parameters ;-)

I'm not sure I get your point. This is totally as expected, since
(apply = 1 1 '(1 1)) is equivalent to (= 1 1 1 1) which should
return true. Similar (= 1 1 1 2) should return false.

Sincerely
Meikel

Frantisek Sodomka

unread,
Aug 6, 2008, 5:49:04 PM8/6/08
to clo...@googlegroups.com
I was just pointing out equivalence, because I know only (apply f
some-list-here) and not (apply f x y ... some-list-here). That's all.

Frantisek

Rastislav Kassak

unread,
Aug 6, 2008, 5:53:29 PM8/6/08
to clo...@googlegroups.com
If 'and' is macro so it can't be used in HOFs what is the pure fn
alternative for 'and' in such scenarios?
Anything except "create your own and function" would be helpful.
No current implementation complication, just wondering, building
knowledge base for future. :)

Rich Hickey

unread,
Aug 6, 2008, 6:10:56 PM8/6/08
to Clojure


On Aug 6, 5:53 pm, "Rastislav Kassak" <kasou...@gmail.com> wrote:
> If 'and' is macro so it can't be used in HOFs what is the pure fn
> alternative for 'and' in such scenarios?
> Anything except "create your own and function" would be helpful.
> No current implementation complication, just wondering, building
> knowledge base for future. :)
>

(every? identity [1 2 3 42])
-> true

Rich

Chas Emerick

unread,
Aug 7, 2008, 8:02:12 AM8/7/08
to clo...@googlegroups.com

On Aug 6, 2008, at 10:41 AM, Rich Hickey wrote:
>
> On Aug 6, 2:10 am, "Frantisek Sodomka" <fa...@intricatevisions.com>
> wrote:
>> I understand that "and" needs to be a macro. Try this one though:
>>
>
>> user=> (apply and2 '(true false))
>
> You shouldn't be applying macros. They are meant to be called by the
> compiler. The fact that they are implemented as functions is an
> implementation detail.
>
> It has been requested that I make such usage an error in an effort to
> prevent such mistakes, and I have done so.
>
> Here's the new behavior.
>
> (apply and '(true false))
> -> java.lang.Exception: Can't take value of a macro: #'clojure/and
>
> Rich

I absolutely understand why one shouldn't apply a macro; however,
this change also makes it impossible to pass a macro as an argument,
which seems wrong to me. For example, I've been using
clojure.contrib.import-static, which allows one to import static
methods of a class into a namespace, like so:

(import-static org.apache.hadoop.hbase.util.Bytes
toString toBytes toInt toLong)

This makes toBytes, toInt, etc., "top-level" members in the current
namespace. I'm then able to pass them around like regular functions,
which is clearly very handy.

That's a simple example, and I'm sure that import-static could be
implemented using regular functions, but that's besides the point.
As long as a macro is being used in function position (and not being
applied), is there any particular harm to allowing them to be passed
as arguments? By all means, ensure that they're not applied, but
doing more than that seems unnecessarily restrictive.

- Chas

Graham Fawcett

unread,
Aug 7, 2008, 9:38:14 AM8/7/08
to clo...@googlegroups.com
Hi Chas,

On Thu, Aug 7, 2008 at 8:02 AM, Chas Emerick <ceme...@snowtide.com> wrote:
> I absolutely understand why one shouldn't apply a macro; however,
> this change also makes it impossible to pass a macro as an argument,
> which seems wrong to me.

Whether you use (fn [f] (apply f ...)) or (fn [f] (f ...)), you're
still applying a function at runtime, because "f" is an argument in
both of these expressions. The presence of "apply" isn't what makes
passing in macros wrong; it's when they are applied that matters.

For example, I've been using
> clojure.contrib.import-static, which allows one to import static
> methods of a class into a namespace, like so:
>
> (import-static org.apache.hadoop.hbase.util.Bytes
> toString toBytes toInt toLong)

That could be implemented as a function, as you suggest -- the macro
is just sugar. (I like that clojure/import and clojure/refer are
functions, not macros, for this very reason -- wishing to save a few
quote-marks and brackets isn't worth adding a macro and losing a
first-class function.)

> That's a simple example, and I'm sure that import-static could be
> implemented using regular functions, but that's besides the point.
> As long as a macro is being used in function position (and not being
> applied), is there any particular harm to allowing them to be passed
> as arguments? By all means, ensure that they're not applied, but
> doing more than that seems unnecessarily restrictive.

The sticking point is that macros are evaluated at compile-time;
passing macros to be called in higher-order functions would require
that macros were evaluated at runtime. In effect, the higher-order
function would need to recompile part of itself dynamically in order
to correctly apply the macro.

Best,
Graham

Frantisek Sodomka

unread,
Aug 7, 2008, 5:26:07 PM8/7/08
to clo...@googlegroups.com
Function "none=" could also be named "unique?".

Just a suggestion...

Frantisek


On Wed, 06 Aug 2008 22:36:43 +0200, Rich Hickey <richh...@gmail.com>
wrote:
>

Randall R Schulz

unread,
Aug 7, 2008, 5:49:43 PM8/7/08
to clo...@googlegroups.com
On Thursday 07 August 2008 14:26, Frantisek Sodomka wrote:
> Function "none=" could also be named "unique?".

Even better would be "distinct?"


> Just a suggestion...
>
> Frantisek


Randall Schulz

Chas Emerick

unread,
Aug 8, 2008, 9:37:26 AM8/8/08
to clo...@googlegroups.com

On Aug 7, 2008, at 9:38 AM, Graham Fawcett wrote:

> The sticking point is that macros are evaluated at compile-time;
> passing macros to be called in higher-order functions would require
> that macros were evaluated at runtime. In effect, the higher-order
> function would need to recompile part of itself dynamically in order
> to correctly apply the macro.
>
> Best,
> Graham

FWIW, Rich set me straight in irc :-)

I had been using macros defined by import-static in a code path that
was eval-ing certain forms, which was silently making the macros look
like they were behaving like first-class functions.

- Chas

Rich Hickey

unread,
Aug 11, 2008, 10:04:24 AM8/11/08
to Clojure


On Aug 7, 5:49 pm, Randall R Schulz <rsch...@sonic.net> wrote:
> On Thursday 07 August 2008 14:26, Frantisek Sodomka wrote:
>
> > Function "none=" could also be named "unique?".
>
> Even better would be "distinct?"
>

I considered that, and chose none= to map to CL's /=.

But I agree, distinct? is better, so I've changed it to that.

Thanks for the prod,

Rich
Reply all
Reply to author
Forward
0 new messages