3

I'm inspired by clojure's 1.5 cond-> macro.

Similarily, I want to create a macro of the same idea, applied to the function map. However, I have no idea where to start.

For example, I can't find the source for cond->. (probably because it's not released yet)

Any suggestions?

3
  • Could you explain "the same idea, applied to the function map"? Commented Jan 10, 2013 at 1:38
  • @mobyte "the same idea" as in using map as the function among a series of statements for the purpose making code readable. Commented Jan 10, 2013 at 3:13
  • 1
    Could you give an example of usage? Commented Jan 10, 2013 at 3:33

3 Answers 3

3

There is the source of cond-> https://github.com/clojure/clojure/blob/master/src/clj/clojure/core.clj#L6742

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for that reference! It seems obvious now to look for it there first.
2

there are a variety of threading macros from the pallet project folks including apply-map-> which looks close to, though not exactly what you are looking for.

(letfn [(apply-map-
          [arg f arg-coll]
          `(let [arg# ~arg]
             (apply ~f arg#
                    ~@(butlast arg-coll)
                    (apply concat ~(last arg-coll)))))]

  (defmacro apply-map->
    "Apply in a threaded expression.
   e.g.
      (-> :a
        (apply-map-> hash-map 1 {:b 2}))
   => {:a 1 :b 2}"
    [arg f & arg-coll]
    (apply-map- arg f arg-coll))

Perhaps there will be enough examples there for you to pick out what you need.

Comments

2

If I understand -- you want to write a macro that takes a list of partial function calls, and for each one, adds map (or apply map) to the beginning, and the previous result to the end?

While this doesn't directly answer how to write that macro, I wanted to point out that you have a couple of alternatives.

Factor out map

This is always true for pure functions:

(=
  (map g (map f coll))
  (map (comp g f) coll))

The refactored version only walks the collection once, and no intermediate collections need to be made.

Here's what it looks like with threading:

(=
  (->> coll
       (map f)
       (map g))

  (map #(->> % f g) coll))

Here's a concrete example in JS.

Transducers

Transducers are another pattern for doing this kind of thing in Clojure that work on more than just map. They're sort of an abstraction over reducer functions. Clojure's map / filter / reduce (etc.) will create a transducer if called without a collection. You can chain them with comp and use them in various contexts (lazy, eager, observable, whatever). Rich Hickey's talk on them is a good intro.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.