Welcome to Clojure!

As others have noted, there are quite a few threading macros so your example 
could become:

        (-> blah
            (do-this)
            (->> (do-that arg))
            (as-> s (do-the-other a1 s a2)))

Or:

        (-> (->> blah
                 (do-this)
                 (do-that arg))
            (as-> s (do-the-other a1 s a2)))

How elegant the result ends up being will depend on exactly how many first 
position, last position, and “in the middle” position your expressions are. One 
thing to be aware of is that, idiomatically, Clojure tries to follow the 
pattern that the “important” argument is always the first one (the thing being 
“operated on”), except for collection functions where it is always the last 
one. The former lends itself to -> and the latter to ->> (and partial) so if 
you have an expression that seems to be a mixture of both, think hard about 
whether the functions are following that idiom.

In your example, if blah is a collection, then do-the-other probably ought to 
be:

        (do-the-other a1 a2 coll)
       ;; and use ->> blah across all three calls

If blah is the “important” argument, then maybe do-that and do-the-other should 
have it consistently in the first position:

        (do-that s arg)
        (do-the-other s a1 a2)
        ;; and use -> blah across all three calls

If you still need to mix -> and ->> perhaps break the expression up and use let 
to bind appropriate names to the subexpressions for clarity of intent.

For the conditional throw code, I’d suggest two possible alternatives:

        (let [x blah
              y bim
              _ (when-not (condition y) (throw …))
              z blob]
          …)

The _ is just a convention for “this is unused”. Or, if your blob does not 
depend on y, simply reorder things:

        (let [x blah
              y bim
              z blob]
          (when-not (condition y) (throw …))
          …)

As for clojure.test/is – if you want something a bit more expressive that is 
still concise, I’d recommend Expectations http://jayfields.com/expectations/ -- 
we switched to this from clojure.test several years ago and we’ve been very 
happy with it:

        (expect value expression)
        (expect predicate? expression)
        (expect SomeException expression)

To us, that’s a very natural way to write tests. clojure.test feels a bit 
“imperative” since it’s “assert this, assert that”. Mind you, testing is very 
subjective and I know there are folks who won’t like the opinionated way 
Expectations wants you to write your tests.

Hope that helps?

Sean Corfield -- (970) FOR-SEAN -- (904) 302-SEAN
An Architect's View -- http://corfield.org/

"If you're not annoying somebody, you're not really alive."
-- Margaret Atwood

On 9/28/16, 7:26 AM, "clojure@googlegroups.com on behalf of p...@pwjw.com" 
<clojure@googlegroups.com on behalf of p...@pwjw.com> wrote:

Hi.

I'm new to clojure, and it is quite lovely. The threading model is great, the 
emacs integration is super, and the tasteful lisp extensions are good. A very 
nice programming environment all around. 

But as I write more code I find a couple of structures I'm using a lot which 
seem related to me not knowing idioms for a couple of uses cases. So thought 
I'd ask and see if you have any suggestions. 

Apologies if this is covered elsewhere. And if I should read some existing 
documentation I didn't find, I apologize for missing it. And thanks in advance 
for your time reading!

First the thrush operators (-> and ->>) are super handy. But I find myself 
needing to 'move' arguments every now and then. So I get code which looks like

(->> blah
     (do-this)
     (do-that arg)
     ((fn [s] (rearrange arg s arg))))

quite a lot.The alternate is a big nested let like

 (let  [ first   (blah)
          second  (do-this first)
          ...
          result  (wrap-it-up fourteenth) ]
    result)

for sort of sequential application where arguments fall in different 'spots'. 
So I sort of find myself wanting to write a 'positional-thrush' macro like

(-%> blah
     (do-this %)
     (do-that arg %)
     (do-the-other a1 % a2))

where % is replaced with the output of the prior. But no such operator exists 
as far as I can see. So either I've had a good idea (which is unlikely since 
I'm super new to the language) or there's some other idiom you all use for this 
pattern which I've missed.

The second is smaller, but is more a question. clojure.test seems to only have 
'is' so for things like equality I end up writing (is (= (...) (...))) a lot. 
Or to test if an exception is thrown (is (thrown? ...)). That's OK, but I'm 
wondering what led to that decision rather than having is-eq and is-thrown and 
so on (considering the core language has shortcuts like when and unless and 
if-not so the compound macros seem idiomatic).

The last is sort of related to the first. Sometimes I'm assembling a data 
structure in a set of operators and I write them with a let or a -> and half 
way through I have an error condition I want to check. In a mutable procedural 
language you would do something like

  x = blah
  y = bim
  if (! (condition (y))) throw "y doesn't meet condition"
  z = blob

I don't see a good idiom for this. I have to split and nest lets for instance

(let [x (blah) y (bim) ]
  (if (condition (y)) (throw ...)
     (let [ z (blob) ] 
      ))

which seems a bit ugly.  I sort of want a let-with-test or a thrush-with-test 
so something which looks like

(-%?>  (init)
     (operator-1 %)  (post-condition)
     (operator-2 %)  (post-condition) )

where if I don't have a post condition I could just use 'true'. Then this 
expands to doing a quick '(if (not (postcondition (intermedia-result)))) 
throw...)

but that's a crazy thing to want. So curious how you all tackle this.

Thank you all for your consideration. And apologies again if this is covered 
elsewhere or I should have asked in a different forum.

Best,

  Paul




-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to