BIRKEY CONSULTING

ABOUT  RSS  ARCHIVE


Posts tagged "clojure":

13 Jun 2021

Let and Binding macros in Clojure

Clojure has number special forms. Among them are let and binding that are implemented as macros. For new comers to Clojure, above can be confusing to understand, which I hope to address in this blog post. If you have read "Programming Clojure" book, you might be thinking that it is easy to use them correctly considering following straightforward example:

(def x 7) ;; bind the var x to the value 7
(defn print-x [x]
  (println x))

(let [x 9]
  (print-x)) ;; prints 7

(binding [x 9]
  (print-x)) ;; prints 9

Why? Because let creates a lexical scoped vars, which is local to the code block or functions where it is initially defined while def creates a global var that is visible to all functions under the namespace that you are in. Therefore, in the example above, let just created a new "x" with the value of 9. But it is not local to the function "print-x". That is to say, "print-x" have no knowledge of the local scoped binding that is created by let. binding macro instead creates a new binding for the already existed var, "x" with the value of 9. Since "print-x" is evaluated within the binding form, the newly bound value is visible to any chained calls within the form. All nice and easy. However, it is not that obvious to understand and use them correctly. Look at following example:

(def x 7)
(def y 9)

(let [x 5 y x] y) ;; returns 5
(binding [x 5 y x] y) ;; returns 7

let example is just fine. It created a new var "y" with the value of 5 bound to it. But what is going on with the binding example? If we dig little deeper to Clojure API doc, we learn that the new bindings in binding are made in parallel, not sequential as it is in let. Therefore, existing var "y" gets bound to the root binding of "x" not the overshadowed value of "x", which is the case in the let example. OK, so far so good. Let us look at another example:

(defn print-x [& args]
  (println "print-x prints: " args))
(defn print-y [& args]
  (println "print-y prints: " args))
(let [print-x print-y] (print-x 123)) ;; print-y prints: (1 2 3)
(binding [print-x print-y] (print-x 123)) ;; print-y prints: (1 2 3)
(binding [print-x print-y] #(print-x 123)) ;; prints
					     ;; cryptic "#<user$eval__28$fn__30
					     ;; user$eval__28$fn__30@bdb503>"
((binding [print-x print-y] #(print-x 123))) ;; print-x prints: (1 2 3)

All the lines but the last two are pretty straight forward. But how about the last line? Shouldn't it call "print-y" function? Not really. It is because the anonymous function is evaluated outside of the binding form. The "#<user$eval_28$fn_30 user$eval_28$fn_30@bdb503>" is an indication that anonymous function did not get evaluated. The extra parens evals above form. Ok, now, how do you make sure it evaluates within the binding form? Just enclose the anonymous function within parenthesis. What do we learn from all of the above? Here are the summary that helps one use let and binding correctly:

Tags: clojure
02 Feb 2019

Thoughts on Elixir Community by a Clojure Developer

I have been building systems in Clojure/ClojureScript for the the last 7 years or so. I enjoy using it to solve day to day problems. It is still my go-to language of choice and I love the fact that it guides me to think about problem at hand with very data centric way. As a tiny example of this, consider a feature where you need to toggle the sort ordering:

(defn toggle-order [order]
  (order {:asc :desc
	  :desc :asc}))

It is tiny but mighty. There is no if/else/case etc and it is easy to read, which is extremely important as your program grows due to needed complexity. Speaking of being easy to read, I could not help but to quote following from SICP book:

Our design of this introductory computer-science subject reflects two major concerns. First, we want to establish the idea that a computer language is not just a way of gettng a computer to perform operations but rather that it is a novel formal medium for expressing ideas about methodology. Thus, programs must be written for people to read, and only incidentally for machines to execute. Second, we believe that the essential material to be addressed by a subject at this level is not the syntax of particular programming-language constructs, nor clever algorithms for computing particular functions efficiently, nor even the mathematical analysis of algorithms and the foundations of computing, but rather the techniques used to control the intellectual complexity of large software systems.

For me, Using Clojure and Datomic professionally has been a game changer not only in terms of being more problem solving focused but more importantly a paradigm shift for taming domain complexity. It has helped me deliver robust, high performance systems within time and budget. However, having bitten by half baked distributed systems made up of tiny services done as afterthoughts, I have always been on the lookout for more robust distributed system development story. Then I found Elixir, a functional language running on Erlang VM called BEAM. After spending some time attending ElixirConf US and couple of meetups in ErlangElixirSF, I am posting what I really liked about Elixir community that Clojure Community might benefit:

I hope someone from both community find above helpful.

Tags: clojure elixir
26 Oct 2018

Datafy and tap> in Clojure 1.10

I noticed couple of new features being added to Clojure 1.10. One is tap, which is added to the core ns, and the other is datafy, which is added to clojure.datafy ns.

tap essentially is an atom holding set of fns of single arity, which will be asynchronously called on any value you you send via tap>. You can add a single arity fn to the tap via (add-tap f) and remove the fn via (remove-tap f). Note that you have to remember the fn you added so you can remove it. Otherwise, you have no way of removing the fn, which is an inconvenience but there might be a reason why it is the way it is. I am not sure about its intended use cases but I know it comes handy when you have a set of transformation (important: order of those transformation should not matter) that you would like to apply to any value asynchronously. I can think of following uses cases for tap:

Enough being said, let us see with a simple example to cover first uses case I said above.

(def context (StringBuilder.))

(defn ->context [x]
  (doto context
    (.append x)))

;; Then let us add above fn to the tapset
(add-tap ->context)
;; Then from any where of our running code, we can do:
(tap> "******* tap start ********\n ")
(tap> "runing.......................\n")
(tap> "******* tap end **********\n ")

;; It will be executed in a separate dedicated thread and will not
;; block or interfere with our running code. Then we print out the context:
(str context)
;; which results in:
;;******* tap start ********
;; runing.......................
;;******* tap end **********

;; Remember to remove the ->context fn once you are done with that session:
(remove-tap ->context)
;; If there is no fn added to the tap, any values you send to tap will be discarded.
(tap> "your magic") ;; your magic will be discarded.

The other one I noticed is datafy, which I am more excited about. I am already using it to find out about java classes members, methods and its object graph. Let us take a java class String as an example.

(require '[clojure.datafy :as d])
(d/datafy String) ;; which will print all about its members in a nice clojure ds

;; let us write an fn to give use any member that we would like to find more about:
(defn member-lookup [class member]
  (->> class
       d/datafy
       :members
       (filter (fn [[k v]] (= (symbol member) k)))))
;; then use it to find about "intern"
(member-lookup String "intern")
;; returns:
([intern
  [{:name intern,
    :return-type java.lang.String,
    :declaring-class java.lang.String,
    :parameter-types [],
    :exception-types [],
    :flags #{:public :native}}]])

;; One can learn a lot about this method from above ds. "intern" is a
;; public native method that takes no argument, called on string object
;; and returns string like this:
(.intern "test") ;; => "test"

This means we can use above information to create Clojure fns on the fly for java inter-op. One great use case would be to generate Clojure fns out of AWS Java SDK, which I might do if time permits.

Tags: clojure
04 Oct 2018

Visualize Google search results from Clojure REPL

While back when I was learning Clojure, I have written a small lib that allows me directly generate bar chart out of google search results from Clojure. I updated it with latest deps and added a fn to save the bar-chart to a png file. You can checkout the project here: https://github.com/oneness/gcount. Here is a one liner to get you going:

git clone git@github.com/oneness/gcount.git && cd gcount && lein repl

Once you are in repl, you can type following:

(search-view-terms ["Clojure Programming" "Elixir Programming" "Elm Programming"])

Above will produce something like this: google-search-result.png

Tags: clojure
Other posts