Clojure Programming/FAQ

From Wikibooks, the open-content textbooks collection

Jump to: navigation, search

Contents

[edit] Q: What would you like to see in the FAQ?

  • What versions of Java have been tested?
  • What versions of Java are supported?
  • Is Clojure object-oriented?

[edit] Q: How do I declare a variable?

As a functional language, Clojure discourages the use of variables. If it takes more thought initially to construct solutions that don't need variables, please try to expend the effort - it will repay you many times over. eg:

  int i;
  int sum;
  for (i=1;i<=100;i++,sum+=i);

Can be written without variables in Clojure as

(reduce + (range 100))

Clojure does support variables but you should read about them fully before using them to understand their semantics. If you are really stuck and want a quick solution, you can use def:

(def a 5)
(def a 6)

But this is not recommended and is only suggested as a workaround until you can more fully explore Clojure.

[edit] Q: Why doesn't contains? do what I expect on vectors and lists

Sequential lookup is not an important operation. Clojure includes sets and maps, and if you are going to be looking things up you should be using them. contains? maps to java.util.Set.contains. The fact that java.util.Collection also has contains is, IMO, a mistake, as you really can't write code to an interface with dramatically varying performance characteristics. So, lookups in sets and maps take priority and get the best name - contains? People write naive programs that do linear lookups with contains() in other languages, and get correspondingly bad n-squared performance - that's not an argument for encouraging that in Clojure. If they get an explanation of why it's a bad idea, and how to use sets and maps, that's fine.

[edit] Q: How can I lookup what methods a Java object contains

You can use the clojure-contrib "show":

user=> (use '[clojure.contrib.repl-utils :only (show)])
nil
user=> (show Object)
===  public java.lang.Object  ===
[ 0] <init> ()
[ 1] equals : boolean (Object)
[ 2] getClass : Class ()
[ 3] hashCode : int ()
[ 4] notify : void ()
[ 5] notifyAll : void ()
[ 6] toString : String ()
[ 7] wait : void ()
[ 8] wait : void (long)
[ 9] wait : void (long,int)
nil
user=> 

Or if you don't want to use "clojure.contrib" then the following should do some of the work:

user=> (map #(.getName %) (.getMethods Object))
("wait" "wait" "wait" "hashCode" "getClass" "equals" "toString" "notify" "notifyAll")
user=> 

[edit] Q: How can I convert a Java HashMap to a clojure map?

user=> (doto (new java.util.HashMap) (.put "a" 1) (.put "b" 2))
#<HashMap {b=2, a=1}>
user=> (def hm (doto (new java.util.HashMap) (.put "a" 1) (.put "b" 2))) 
#'user/hm
user=> hm
#<HashMap {b=2, a=1}>
user=> (def h (into {} hm))
#'user/h
user=> h
{"a" 1, "b" 2}
user=> (h "a")
1
user=> 

[edit] Q: How can I loop through something and produce a result collection of a different size?

Suppose I need to process the lines of a text file, and every now and then (based on the line contents) create an object and add it to a list of results. (e.g. a simple parsing of a text file). For example maybe every 5 or 6 lines there is a blank line and I use that to create an object based on the previous lines. Because the number of lines is different I can't use map or anything functional, so it seems. Is with-local-vars required, or is there some more elegant way?


The following code searches through a set of lines and returns matching lines. The def lines simply gives us a collection to work with. The for statement iterates through the "lines" and assigns each entry to "line". For each line, the :when clause is called. If that returns true, then the body of the for is executed, in this case, simply return line. The results are put into a sequence, same as the map function but only containing the matching elements.

user> (def lines ["aa" "bb" "cc" "dd"])
-> #'user/lines
user> (for [line lines :when (#{"bb"} line)] line )
-> ("bb")

The filter function accomplishes a similar thing

(filter #{"bb"} lines)