noMAD
noMAD

Reputation: 7844

Simple thread macro implementation

Very new to clojure so might be a noob question but here it is. So I read that the -> macro will invoke functions in sequence and I understand how this works. (-> (+ 1 2) (* 10)) which results in 30

But why does this not do the same?

(defn testing-> [a b]
  (list a b)
  first)

This returns a function first and not "a" when called as (testing-> "a" "b"). What am I missing here? Using it in the wrong way?

Upvotes: 1

Views: 128

Answers (2)

noisesmith
noisesmith

Reputation: 20194

A macro is something that restructures its input before it gets compiled.

user> (macroexpand '(-> (+ 1 2) (* 10)))
(* (+ 1 2) 10)

testing-> is a function, not a macro, so it does not restructure the input. You would need to rearrange the input forms before evaluation to get a behavior similar to ->. Every valid form needs to be translated into the standard clojure syntax at compile time, which is done via reader-expansion and macro-expansion.

Macro construction uses standard Clojure functions, but the semantics are somewhat unique (a macro should return the form that will be used at runtime). You can use the clojure.repl/source macro to see how various macros are implemented.

Any operations you need can be expressed as functions, and general creating macros should be avoided unless you need a new syntax.

Upvotes: 3

Arthur Ulfeldt
Arthur Ulfeldt

Reputation: 91534

the -> needs to be in the body of the function. it's not magic attributed to functions ending with -> but literally a macro whose name is -> which takes a sequence of things to do and produces a new expression with the same things nested each inside the next:

(defn testing [a b]
  (-> [a b]
      list
      first))

in this exampel, when the -> macro runs it produces a new expression which looks like:

(defn testing [a b]
  (first (list [a b])))

For another example, when you call -> with the arguemnts (+ 1 2) (* 10) it returns the expression (* (+ 1 2) 30) which is then evaluated as normal Clojure code.

PS: a macro is a function which takes a Clojure expression and produces another Clojure expression. These run In the middle of the compilation cycle and you can see what they are doing with the macroexpand-1 function.

Upvotes: 5

Related Questions