Appendix F. A cheat sheet for Clojure’s DSL-friendly features

This appendix will assist you as you become familiar with the DSL-friendly features of Clojure. Please don’t treat this information as a comprehensive language overview. For a more complete and detailed discussion of the language and its syntax, see the reference in section F.2.

F.1. DSL-friendly features of Clojure

Clojure is a functional programming language that’s built on top of the JVM. It’s dynamically typed, with optional type hints and type inference, and is targeted as a general-purpose programming language. Clojure is a dialect of Lisp and compiles directly to JVM bytecode. It’s homoiconic and has strong features of concurrency control built in the language.

Besides the features described in the table, Clojure has lots of other features related to concurrency and state management, lazy sequences, sequence-comprehensions and looping, and many advanced data structures. For more on these, refer to [1] in section F.2.

Table F.1. Clojure feature overview
Functional—organize DSLs around functions
You organize your entire DSL as a collection of functions. In Clojure, functions are first-class artifacts with strong support for higher-order functions and closures. Anonymous functions are also supported. In spite of the fact that Clojure is built upon Java, the language is predominantly functional. You can go down to the Java level and invoke object semantics, but idiomatic Clojure is functional. (str "hello" " " "world")
=> "hello world"
(count [1 2 3 4 5])
=> 5
(+ 12 20)
=> 32 Prefix notation is the normal order of the day. Note: Clojure is homoiconic. Note that every function invocation is a list that begins with the function name. (filter even? [1 2 3 4])
=> (2 4) even? is a Clojure function that returns true if the input is an even number. In the previous example, we pass the function even? as a parameter to filter, which applies even? to every element of the passed sequence. (filter #(or (zero? (mod % 3))
(zero? (mod % 5)))
[1 3 5 7 9 10 15])
=> (3 5 9 10 15) filter can also take an anonymous function.
Functional—function definition
You define a function using defn. That’s pure syntax, which I illustrate in the example. The most interesting part is that in Clojure (like any other Lisp variant), a function is also data that starts with a symbol. (defn ^String greet
"Greet your friend"
[name]
(str "hello, " name)) defn starts the beginning of a function definition. The next part is the documentation associated with the function definition, called the docstring. Then we have the parameter list in a vector, and finally the body of the function. Optionally, you can have metadata with the ^ prefix. Here it indicates the return type of the function. The whole function definition is also a Clojure list that contains members for every part of the definition.
Designing abstractions
The Clojure way Traditional OO way
  • Public fields
  • Immutable objects
  • Polymorphism through multimethods and protocols
  • No implementation inheritance
  • All data is hidden inside classes through private members
  • Objects are mutable
  • Polymorphism through inheritance hierarchies, which can mean inheritance of interface or implementation
  • Implementation inheritance allowed
Sequences
Every aggregate data type in Clojure is a sequence. You can treat sequences uniformly through a set of APIs that apply equally to every member of the sequence family. You can also treat all Java collections as Clojure sequences. Take a look at the examples. (first '(10, 20, 30))
=> 10
(rest [10, 20, 30])
=> (20, 30)
(first {:fname "rich" :lname "hickey"})
=> [:fname "rich"] In the code snippet:
  • The first example invokes first on a List.
  • The second example invokes rest on a Vector.
  • The third example invokes first on a Map.
Sequences are functions
Clojure treats every sequence type as a function. This follows from the mathematical definitions of the sequences. Here’s a list of the ways we can express Clojure’s sequences mathematically:
  • A Vector is a function of its position.
  • A Map is a function of its key.
  • A Set is a function of membership.
(def colors [:red :blue :green])
(colors 0)
=> :red
(def room {:len 100 :wd 50 :ht 10})
(room :len)
=> 100
(def names #{"rich hickey" "martin odersky"
"james strachan"})
(names "rich hickey")
=> "rich hickey"
(names "dennis Ritchie")
=> nil
Creating sequences
Clojure offers a number of functions that you can use to create sequences. Many of them offer a lazy sequence as a result and can be used to generate infinite sequences. (range 0 10 2)
=> (0 2 4 6 8)
(repeat 5 3)
=> (3 3 3 3 3)
(take 10 (iterate inc 1))
=> (1 2 3 4 5 6 7 8 9 10)
Filtering sequences
Clojure offers combinators that you can use to filter a sequence. Always prefer using these combinators instead of coding an explicit recursion. (filter even? [1 2 3 4 5 6 7 8 9])
=> [2 4 6 8]
(take 10 (filter even? (iterate inc 1)))
=> [2 4 6 8 10 12 14 16 18 20]
(split-at 5 (range 10))
=> [(0 1 2 3 4) (5 6 7 8 9)]
Transforming sequences
Clojure offers lots of combinators that transform an existing sequence. They take as input one sequence and generate another sequence or value by applying some transformation. (map inc [1 2 3 4])
=> (2 3 4 5)
(reduce + [1 2 3 4])
=> 10
Persistent data structures and immutability
In Clojure, all data structures are immutable and persistent. This means that after you make changes to an object, you can access all historical versions of the same object without incurring additional overhead in storage requirements. (def a [1 2 3 4])
(def b (conj a 5))
a
=> [1 2 3 4]
b
=> [1 2 3 4 5]
Macros
The secret sauce of DSL design in Clojure is macros. Macros are artifacts that get expanded to valid Clojure forms during the macro-expansion phase. Macros are a very potent tool to use to design custom syntax constructs in your DSL. (defmacro unless [expr form]
(list 'if expr nil form)) The macro defines a control structure like if or while that you can use just like normal Clojure forms.

F.2. References

  1. Halloway, Stuart. 2009. Programming Clojure. The Pragmatic Bookshelf.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.38.117