Enhancement proposal to -> and ->>

33 views
Skip to first unread message

Christophe Grand

unread,
Jan 26, 2010, 2:07:07 AM1/26/10
to cloju...@googlegroups.com
In the middle of a thread first (or thread last) form, I often need
to use a form which requires its "preferred" arg in last (or first,
respectively) position.

Currently one can switch from -> to ->>, eg:
user=> (-> [] (conj 1) (into [2 3]) (->> (map inc) (mapcat #(vector %
%))) vec (conj 5 5))
[2 2 3 3 4 4 5 5]

But one cannot switch from ->> to -> -- or I didn't find how.

My proposal is to make ->> and -> recognize each other and switch from
thread first to thread last.
One could then rewrite the example above:
(-> [] (conj 1) (into [2 3]) ->> (map inc) (mapcat #(vector % %)) ->
vec (conj 5 5))

See http://github.com/cgrand/clojure/commit/9f2e7ed8c678d5619ff7e8baad74a847b07a7973
for a commit implementing this proposal.
This patch is compatible with -> and ->> destructuring
(http://www.assembla.com/spaces/clojure/tickets/211).

Christophe

Sean Devlin

unread,
Jan 26, 2010, 2:15:53 AM1/26/10
to cloju...@googlegroups.com
Okay, just to make sure I've got this. You example:

> (-> [] (conj 1) (into [2 3]) ->> (map inc) (mapcat #(vector % %)) ->
> vec (conj 5 5))


Expands to

(conj (vec (mapcat #(vector % %) (map inc (into (conj []) [2 3])))) 5 5)

Slick.

> --
> You received this message because you are subscribed to the Google Groups "Clojure Dev" group.
> To post to this group, send email to cloju...@googlegroups.com.
> To unsubscribe from this group, send email to clojure-dev...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/clojure-dev?hl=en.
>

Laurent PETIT

unread,
Jan 26, 2010, 2:54:31 AM1/26/10
to cloju...@googlegroups.com
2010/1/26 Sean Devlin <francoi...@gmail.com>:

>        Okay, just to make sure I've got this.  You example:
>
>> (-> [] (conj 1) (into [2 3]) ->> (map inc) (mapcat #(vector % %)) ->
>> vec (conj 5 5))
>
>
> Expands to
>
>  (conj (vec (mapcat #(vector % %) (map inc (into (conj []) [2 3])))) 5 5)

or rather
(conj (vec (mapcat #(vector % %) (map inc (into (conj [] 1) [2 3])))) 5 5)

(you missed the 1 in the last conj)

Christophe Grand

unread,
Jan 26, 2010, 5:25:56 AM1/26/10
to cloju...@googlegroups.com
On Tue, Jan 26, 2010 at 8:15 AM, Sean Devlin <francoi...@gmail.com> wrote:
>        Okay, just to make sure I've got this.  You example:
>
>> (-> [] (conj 1) (into [2 3]) ->> (map inc) (mapcat #(vector % %)) ->
>> vec (conj 5 5))
>
>
> Expands to
>
>  (conj (vec (mapcat #(vector % %) (map inc (into (conj []) [2 3])))) 5 5)

Yes, that's right (modulo the missing 1 pointed out by Laurent).
Of course, while not that useful, you can also repeat the current
threading symbol: (-> a -> b) and (->> a ->> b) are respectively
equivalent to (-> a b) and (->> a b).

Christophe

Meikel Brandmeyer

unread,
Jan 26, 2010, 6:14:33 AM1/26/10
to Clojure Dev
Hi,

On Jan 26, 8:07 am, Christophe Grand <christo...@cgrand.net> wrote:

> (-> [] (conj 1) (into [2 3]) ->> (map inc) (mapcat #(vector % %)) ->
> vec (conj 5 5))

Very nice indeed.

Sincerely
Meikel

Christophe Grand

unread,
Jan 26, 2010, 3:22:24 PM1/26/10
to cloju...@googlegroups.com
btw current patch is buggy (thanks to StartsWithK for pointing it out
on #clojure), this expr:
(and (#{'-> '->> `-> `->>} form) (not (contains? &env form)))
should be:
(and (symbol? form) (#{#'-> #'->>} (resolve form)) (not (contains?
&env form)))

but resolve is defined way after -> and ->>, so it requires either
moving some declarations around or redefining -> and ->> at the end.

Christophe

> --
> You received this message because you are subscribed to the Google Groups "Clojure Dev" group.
> To post to this group, send email to cloju...@googlegroups.com.
> To unsubscribe from this group, send email to clojure-dev...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/clojure-dev?hl=en.
>
>

--
Professional: http://cgrand.net/ (fr)
On Clojure: http://clj-me.cgrand.net/ (en)

Christophe Grand

unread,
Jan 27, 2010, 4:54:33 AM1/27/10
to cloju...@googlegroups.com

Allen Rohner

unread,
Feb 6, 2010, 3:42:11 PM2/6/10
to Clojure Dev
Rather than extending -> and ->>, how about making one arrow to rule
them all. I dislike the proposals for all kinds of new arrows, -> ->>,
-?> -?>>. I'm sure soon there will be more. In effect, we need an
arrow proliferation treaty :-).

How about making -> recognize a special symbol that says "stick the
result of the previous expression here".

(-> [] (conj _ 1) (into _ [2 3]) (map inc _) (mapcat #(vector % %) _)
(vec _) (conj _ 5 5))

This supports thread-first and thread-last, and eliminates the need
for "thread-second" or whatever in the future.

Allen

On Jan 27, 3:54 am, Christophe Grand <christo...@cgrand.net> wrote:
> Fix:http://github.com/cgrand/clojure/commit/8ddf1d8548de4b0e60a58fb55fe6b...

Sean Devlin

unread,
Feb 6, 2010, 4:27:17 PM2/6/10
to Clojure Dev
Something like this?

http://gist.github.com/296970

Sean

Meikel Brandmeyer

unread,
Feb 6, 2010, 4:52:16 PM2/6/10
to cloju...@googlegroups.com
Hi,

Am 06.02.2010 um 21:42 schrieb Allen Rohner:

> Rather than extending -> and ->>, how about making one arrow to rule
> them all. I dislike the proposals for all kinds of new arrows, -> ->>,
> -?> -?>>. I'm sure soon there will be more. In effect, we need an
> arrow proliferation treaty :-).
>
> How about making -> recognize a special symbol that says "stick the
> result of the previous expression here".
>
> (-> [] (conj _ 1) (into _ [2 3]) (map inc _) (mapcat #(vector % %) _)
> (vec _) (conj _ 5 5))
>
> This supports thread-first and thread-last, and eliminates the need
> for "thread-second" or whatever in the future.

See also: http://groups.google.com/group/clojure/browse_thread/thread/66ff0b89229be894/e78c3585589cdbf6

Sincerely
Meikel

ataggart

unread,
Feb 6, 2010, 7:52:53 PM2/6/10
to Clojure Dev
Ever since reading Rich's post about the concept that -> apply to
object/value manipulation whereas ->> apply to sequence-of-values, I
find there's information kept by not munging everything under one
symbol. It might even encourage people design more consistent APIs.

Sean Devlin

unread,
Feb 8, 2010, 10:53:05 PM2/8/10
to Clojure Dev
I think a more versatile arrow is orthogonal to clean APIs.

What if we included something like this in c.c.core? This gets it
widely distributed, and we can see how quickly the community starts
playing with this. If it's a hit, promote it. If it isn't widely
used, it rots in contrib.

Sean

Rich Hickey

unread,
Feb 9, 2010, 6:55:58 AM2/9/10
to cloju...@googlegroups.com
On Mon, Feb 8, 2010 at 10:53 PM, Sean Devlin <francoi...@gmail.com> wrote:
> I think a more versatile arrow is orthogonal to clean APIs.
>
> What if we included something like this in c.c.core?  This gets it
> widely distributed, and we can see how quickly the community starts
> playing with this.  If it's a hit, promote it.  If it isn't widely
> used, it rots in contrib.
>

I think that's a bad approach to library design. We've discussed this
before, and I think the consensus was that a fully parameterized arrow
doesn't bring more utility than it does complexity, isn't in wide
demand other than as an intellectual completeness exercise, and
doesn't offer significant value over:

(let [x []
x (conj x 1)
x (into x [2 3])
x (map inc x)]
...)

Rich

Rich Hickey

unread,
Feb 9, 2010, 7:01:54 AM2/9/10
to cloju...@googlegroups.com

I think this is an interesting idea, but have to say that the
implementation gives me the creeps, especially the use of &env.
Certainly it begs for a version of resolve that takes the environment.

Rich

Christophe Grand

unread,
Feb 10, 2010, 1:38:39 PM2/10/10
to cloju...@googlegroups.com
On Tue, Feb 9, 2010 at 1:01 PM, Rich Hickey <richh...@gmail.com> wrote:
> I think this is an interesting idea, but have to say that the
> implementation gives me the creeps, especially the use of &env.
> Certainly it begs for a version of resolve that takes the environment.

Here is a ticket+patch
http://www.assembla.com/spaces/clojure/tickets/263-Add-an-optional-environment-argument-to---resolve-and-ns-resolve

Christophe

Christophe Grand

unread,
Feb 10, 2010, 5:45:30 PM2/10/10
to cloju...@googlegroups.com
On Tue, Feb 9, 2010 at 1:01 PM, Rich Hickey <richh...@gmail.com> wrote:
> I think this is an interesting idea, but have to say that the
> implementation gives me the creeps, especially the use of &env.
> Certainly it begs for a version of resolve that takes the environment.

The new implementation is creepy in its own way (macro emitting a
macro) but it is open and would allow -?> and -?>> to participate.

See http://github.com/cgrand/clojure/commit/2920f991bb2f7b951554265795fd11c2939b2e4b
and http://github.com/cgrand/clojure/commit/a91e805eabb0dbd54a3e822313e45db82ce9d0d1

Reply all
Reply to author
Forward
0 new messages