Gih's Blog

只言片语

Thrush calls in Common Lisp

2014-09-19 by gihnius, tagged as lisp

Implement the "->" operator of Clojure: http://clojuredocs.org/clojure_core/clojure.core/-%3E in CL, that's funny.

->

Threads the expr through the forms. Inserts x as the second item in the first form, making a list of it if it is not a list already. If there are more forms, inserts the first form as the second item in second form, etc.

(defmacro -> (x &optional (form nil form-supplied-p) &rest more)
  (if form-supplied-p
      (if more
          `(-> (-> ,x ,form) ,@more)
          (if (listp form)
              `(,(car form) ,x ,@(cdr form))
              (list form x)))
      x))

How does it works?

CL-USER> (-> 1
             (+ 1)
             (+ 2)
             (+ 3))

7
CL-USER> 

=== (+ (+ (+ 1 1) 2) 3)

See another example:

CL-USER> (-> 10
             (- 5)
             (- 5)
             (- 5))
-5
CL-USER> 

=== (- (- (- 10 5) 5) 5)

How if I want (- 5 (- 5 (- 5 10)))?

There is ->> to do this. http://clojuredocs.org/clojure_core/clojure.core/-%3E%3E

->>

Threads the expr through the forms. Inserts x as the last item in the first form, making a list of it if it is not a list already. If there are more forms, inserts the first form as the last item in second form, etc.

(defmacro ->> (x &optional (form nil form-supplied-p) &rest more)
  (if form-supplied-p
      (if more
          `(->> (->> ,x ,form) ,@more)
          (if (listp form)
              `(,(car form) ,@(cdr form) ,x)
              (list form x)))
      x))

This one looks more useful sometimes.

CL-USER> (->> (list 1 2 3 4 5)
              (reduce '+)
              (* 2)
              (- 5))
-25
CL-USER> 

=== (- 5 (* 2 (reduce '+ '(1 2 3 4 5))))