Posts Tagged ‘snippet’
Map, Reduce and Filter in Clojure
Map
Map applies a function to each element in a collection and returns a new collection with the results of each function.

user> (map #(+ 10 %1) [ 1 3 5 7 ]) (11 13 15 17)
Reduce
Reduce applies a function on all elements of a collection and returns a value. This value could also be another collection.

user> (reduce * [2 3 4]) 24
Filter
Filter applies a predicate function to each element in a collection and returns a new filtered collection.

user> (filter even? [1 2 3 4 5 6]) (2 4 6)
Clojure futures – A Walkthrough
What is Future?
It is a simple mechanism to execute a snippet of code on a background thread.
How to use Future?
We can use Future in two ways.
1) Using macro “future”
(def f (future (prn "going to sleep...") (Thread/sleep 10000) (prn "slept good")))
2) Using function “future-call”
(defn long-process[] (Thread/sleep 10000)) (future-call long-process)
Under the shell both these ways are equivalent. The macro is syntax sugar and it gets converted to future-call.
Even though “long-process” function is put to sleep for 10 secs, it will return immediately. It returns a “future” object. We can use this object to inspect whether the function has been executed in background thread.
(future-done? f) (future-cancelled? f) (future-cancel f)
Limitations of Future?
As you known clojure comes with a bounded thread pool and unbounded thread pool. Mostly CPU bound operations should be using bounded thread pool and IO operations should be using unbound thread pool. Clojure Future uses unbounded thread pool, so it is good for IO operations but not for CPU bound operations. So for CPU bound operations Future might not be a good choice. But there is a open source project that helps to overcome this limitations. Check out http://github.com/amitrathore/medusa
Parsing XML in Clojure
Problem :
We need to parse a xml string and be able to query using xpath style tag list.
Ex :
<friends> <person> <name>Siva</name> </person> </friends>
I need a function that can do this,
(get-value xml :person :name)
returns “Siva”
Solution :
To parse and query xml we need to do these following three things in clojure.
1) Convert xml string (file) to Struct Map
Clojure core comes with a build in xml library (clojure.xml http://clojure.github.com/clojure/clojure.xml-api.html) that has a parse function which takes in InputStream and returns a struct map that represents xml.
(defn get-struct-map [xml]
(let [stream (ByteArrayInputStream. (.getBytes (.trim xml)))]
(xml/parse stream)))
user> (get-struct-map xml)
{:tag :friends, :attrs nil, :content [{:tag :person, :attrs nil, :content [{:tag :name, :attrs nil, :content ["Siva"]}]}]}
This struct map is cumbersome to query.
2) Convert Struct Map to Zipper Data Structure
“A zipper is a technique of representing an aggregate data structure so that it is convenient for writing programs that traverse the structure arbitrarily and update its contents, especially in purely functional programming languages.” http://en.wikipedia.org/wiki/Zipper_%28data_structure%29
To make it easy for us to traverse we will change struct map to zipper data structure. Clojure comes with zip library ( it is short form for zipper ) http://clojure.github.com/clojure/clojure.zip-api.html
We will this zip library to convert xml struct map to zipper data structure.
user> (clojure.zip/xml-zip xml-struct)
[{:tag :friends, :attrs nil, :content [{:tag :person, :attrs nil, :content [{:tag :name, :attrs nil, :content ["Siva"]}]}]} nil]
3) Use Zip-filter library and query zipper data structure.
Now that we have our xml in zipper data structure we could use zip-filter library that is present in clojure.contrib. http://clojure.github.com/clojure-contrib/zip-filter-api.html
user> (clojure.contrib.zip-filter.xml/xml-> zipper-struct :person :name)
("Siva")
Putting this altogether
(ns com.sivajag.utils.xml
(:import (java.io ByteArrayInputStream))
(:require [clojure.xml :as xml])
(:require [clojure.zip :as zip])
(:require [clojure.contrib.zip-filter.xml :as zf]))
(defn get-struct-map [xml]
(if-not (empty? xml)
(let [stream (ByteArrayInputStream. (.getBytes (.trim xml)))]
(xml/parse stream))))
(defn get-value [xml & tags]
(apply zf/xml1-> (zip/xml-zip (get-struct-map xml)) (conj (vec tags) zf/text)))
user> (get-value xml :person :name)
"Siva"
Happy Coding!!!
Simple clojure multimethod example
user> (defmulti teller (fn [m] (:tell m))) #'user/teller
user> (defmethod teller :b [m] (:b m)) #
user> (defmethod teller :a [m] (:a m)) #
user> (def m {:tell :a :a 1 :b 2})
#'user/m
user> (teller m) 1
user> (def m {:tell :b :a 1 :b 2})
#'user/m
user> (teller m) 2
