-> vs comp

10 views
Skip to first unread message

Sean Devlin

unread,
Oct 16, 2009, 10:22:24 PM10/16/09
to Clojure
I have an idea in my head, and I can't quite put all the details
together. The intent with of this posting is to start a healthy
debate of the merits of -> vs. comp. I know people on this list will
think of something.

After designing my own Clojure libraries for a while, I've come to a
conclusion in the -> vs. comp debate. I think comp & partial is a
better choice than ->, because they return a closure. I believe
working with closures have the following advantages

* It "just works" with higher order functions, like map or filter.
* comp, like any other function, can be swapped out. As long as the
result is a closure, the rest of the code will "just work". This makes
swapping out a monad more straightforward.
* comp & partial can be applied to a list, -> cannot.

Given these reasons, I'd like to make a proposal. Contrib should be
centered around closures, not ->.

In order to generate closures, every function should take parameters
first, and data at the end, so that they work well with partial. When
possible, higher order functions should be given preference over
macros.

samppi

unread,
Oct 16, 2009, 11:55:15 PM10/16/09
to Clojure
Don't forget about the third piece of the puzzle, #() (and fn).
Whenever I need to create a function using ->, I just do #(-> % ...).
It's about as much typing as (comp ...).

Personally, I can go either way—I just kind of wish that there was a
consistent practice for the placement of the most important argument,
whether it's first or last, in both core and contrib.

John Harrop

unread,
Oct 17, 2009, 12:01:11 AM10/17/09
to clo...@googlegroups.com
On Fri, Oct 16, 2009 at 11:55 PM, samppi <rbys...@gmail.com> wrote:
Don't forget about the third piece of the puzzle, #() (and fn).
Whenever I need to create a function using ->, I just do #(-> % ...).
It's about as much typing as (comp ...).

Personally, I can go either way—I just kind of wish that there was a
consistent practice for the placement of the most important argument,
whether it's first or last, in both core and contrib.

While we're at it, let's not forget the fourth piece of the puzzle: swap!, alter, send, and friends, which work best if functions put the data first and parameters after. If the parameters come first, all of them need to be wrapped: instead of (send agent foo param1 param2), say, you need (send agent #(foo param1 param2 %)). Yuck!

(Irony: -> is also like swap!, alter, and their friends in this regard.)

Timothy Pratley

unread,
Oct 17, 2009, 3:44:23 AM10/17/09
to Clojure


On Oct 17, 1:22 pm, Sean Devlin <francoisdev...@gmail.com> wrote:
> Given these reasons, I'd like to make a proposal. Contrib should be
> centered around closures, not ->.

Hi Sean,

-> seems to work nicely for java interop in ways that comp does not. I
think it has its place.

(defn full-screen
"Enables full-screen mode"
[#^Window window]
(later
(->
(GraphicsEnvironment/getLocalGraphicsEnvironment)
.getDefaultScreenDevice
(.setFullScreenWindow window))))

I don't think there is an easy composition equivalent. Java tends to
have quite a few of these chain calls.

Are there any particular examples you are refering to?


Regards,
Tim.

James Reeves

unread,
Oct 17, 2009, 7:22:09 AM10/17/09
to Clojure
On Oct 17, 3:22 am, Sean Devlin <francoisdev...@gmail.com> wrote:
> I have an idea in my head, and I can't quite put all the details
> together.  The intent with of this posting is to start a healthy
> debate of the merits of -> vs. comp.  I know people on this list will
> think of something.

It seems to me you're comparing apples to oranges. -> is a macro for
making code more readable under certain circumstances, whilst comp
performs function composition. They have very different uses.

- James

James Reeves

unread,
Oct 17, 2009, 7:25:32 AM10/17/09
to Clojure
On Oct 17, 4:55 am, samppi <rbysam...@gmail.com> wrote:
> Personally, I can go either way—I just kind of wish that there was a
> consistent practice for the placement of the most important argument,
> whether it's first or last, in both core and contrib.

Well, defining the "most important argument" can be tricky. However,
it would be nice if there were map and filter variants that could be
used with ->.

- James

Laurent PETIT

unread,
Oct 17, 2009, 9:17:48 AM10/17/09
to clo...@googlegroups.com


2009/10/17 James Reeves <weave...@googlemail.com>

FYI, though I haven't used it yet, I've noticed the introduction of ->> in core.clj

(->> data (map my-fn) (filter my-pred))


Meikel Brandmeyer

unread,
Oct 17, 2009, 7:52:00 AM10/17/09
to clo...@googlegroups.com
Hi.

Am 17.10.2009 um 13:25 schrieb James Reeves:

> Well, defining the "most important argument" can be tricky. However,
> it would be nice if there were map and filter variants that could be
> used with ->.

There is also ->>.

(->> some-seq
(filter predicate)
(map function)
(remove other-predicate))

Sincerely
Meikel

Sean Devlin

unread,
Oct 17, 2009, 10:18:52 AM10/17/09
to Clojure
Hmmm... good point about java interop. Didn't consider that.

Sean Devlin

unread,
Oct 17, 2009, 10:30:23 AM10/17/09
to Clojure
Okay, comp on its own is not comparable to ->, good point. Once you
add partial, I think a more direct comparison is possible.

(let [& comp
p partial
((&
(p filter predicate)
(p map function)
(p remove other-predicate))
some-seq))

This is a lot closer to the new ->>.

Anyway, I see now what the main point is. The main point is where
does the data go? I like ->> putting data in the end is a huge step
forward. It makes the libraries designed to use it more flexible,
because it supports both coding styles.
>  smime.p7s
> 3KViewDownload

Wilson MacGyver

unread,
Oct 17, 2009, 12:25:29 PM10/17/09
to clo...@googlegroups.com
Kinda off topic. I didn't realize ->> has been introduced. Is there a
list of new forms that's been
introduced since 1.0?

Thanks
--
Omnem crede diem tibi diluxisse supremum.

Stuart Sierra

unread,
Oct 17, 2009, 6:38:39 PM10/17/09
to Clojure
On Oct 16, 10:22 pm, Sean Devlin <francoisdev...@gmail.com> wrote:
> In order to generate closures, every function should take parameters
> first, and data at the end, so that they work well with partial.

It's really hard to come up with a consistent practice that works well
for all scenarios. Even clojure.core is inconsistent in this regard
-- the sequence fns take the seq at the end, the collection functions
(like assoc) take the collection first.

Whichever way you design your functions, half the time the arguments
will be in the wrong place for what someone wants to do. If you want
a purely compositional style, the only way to do it is to only allow
single-argument functions, a la Haskell.

-SS

Stuart Halloway

unread,
Oct 18, 2009, 2:04:08 PM10/18/09
to clo...@googlegroups.com
I find the suite of ->, ->>, anonymous functions, partial, and comp
sufficient for my needs, with each having its place.

My only grumble is that "partial" is a lot of characters. I would love
a one-character alternative, if it could be reasonably intuitive.

Stu

B Smith-Mannschott

unread,
Oct 18, 2009, 2:21:16 PM10/18/09
to clo...@googlegroups.com
On Sun, Oct 18, 2009 at 20:04, Stuart Halloway
<stuart....@gmail.com> wrote:
>
> I find the suite of ->, ->>, anonymous functions, partial, and comp
> sufficient for my needs, with each having its place.
>
> My only grumble is that "partial" is a lot of characters. I would love
> a one-character alternative, if it could be reasonably intuitive.
>

F# uses >> for functional composition and |> for partial evaluation.
Both as infix operators, of course. Perhaps they'd work for clojure's
prefix syntax?

(def >> comp)
(def |> partial)

what do you think?

Sean Devlin

unread,
Oct 18, 2009, 2:32:34 PM10/18/09
to Clojure
I've been using & and p, respectively.

On Oct 18, 2:21 pm, B Smith-Mannschott <bsmith.o...@gmail.com> wrote:
> On Sun, Oct 18, 2009 at 20:04, Stuart Halloway
>

Robert Fischer

unread,
Oct 18, 2009, 2:32:47 PM10/18/09
to clo...@googlegroups.com
The F# language does partial application through calling the function: if you don't supply enough
arguments, they're partially applied. The |> syntax is for "backwards" (object-y) partial application:

let f x y = ...
let g = f 1
let h = 1 |> f

The |> operator is built-in in F#, but in OCaml (my background), |> can be defined easily enough:
let (|>) x f = f x

~~ Robert Fischer, Smokejumper IT Consulting.
Enfranchised Mind Blog http://EnfranchisedMind.com/blog

Check out my book, "Grails Persistence with GORM and GSQL"!
http://www.smokejumperit.com/gormbook
Reply all
Reply to author
Forward
0 new messages