Book Image

Clojure Programming Cookbook

Book Image

Clojure Programming Cookbook

Overview of this book

When it comes to learning and using a new language you need an effective guide to be by your side when things get rough. For Clojure developers, these recipes have everything you need to take on everything this language offers. This book is divided into three high impact sections. The first section gives you an introduction to live programming and best practices. We show you how to interact with your connections by manipulating, transforming, and merging collections. You’ll learn how to work with macros, protocols, multi-methods, and transducers. We’ll also teach you how to work with languages such as Java, and Scala. The next section deals with intermediate-level content and enhances your Clojure skills, here we’ll teach you concurrency programming with Clojure for high performance. We will provide you with advanced best practices, tips on Clojure programming, and show you how to work with Clojure while developing applications. In the final section you will learn how to test, deploy and analyze websocket behavior when your app is deployed in the cloud. Finally, we will take you through DevOps. Developing with Clojure has never been easier with these recipes by your side!
Table of Contents (16 chapters)
Clojure Programming Cookbook
Credits
About the Authors
About the Reviewer
www.PacktPub.com
Preface

Working with primitive data types


In this recipe, we will review primitive data types that Clojure supports and a few functions that manipulate these types. Here, we will review the following:

  • Using numbers

  • Using strings and characters

  • Using booleans and nil

  • Using keywords and symbols

Getting ready

You only need REPL, as described in the previous recipe, and no additional libraries. Start REPL so that you can review the sample code of primitive types immediately in this recipe.

How to do it...

Let's start with numbers in Clojure data types.

Using numbers

The + function returns the sum of numbers. You can specify any number of numbers as arguments:

(+ 1 2) 
;;=> 3 
(+ 1 2 3) 
;;=> 6 
(+ 1.2 3.5) 
;;=> 4.7 

The - function subtracts the numbers. If a single argument is supplied, it returns the negation of the numbers:

(- 3 2) 
;;=> 1 
(- 1 2 3) 
;;=> -4 
(- 1) 
;;=> -1 

The * function returns the product of numbers:

(* 5 2) 
;;=> 10  
(* 1 2 3 4 5) 
;;=> 120 

The / function returns the numerator divided by all of the denominators. It is surprising for beginners of Clojure that if the numerator is not indivisible by the denominators, it returns a simple fraction. You can check the name of the class by the class function.

In the following example, 10 divided by 3 returns 10/3 and not 3.3333333...

(/ 10 5) 
;;=> 2  
(/ 10 3) 
;;=> 10/3 

To obtain numerical figures after a decimal point, cast the result by a float or double function:

(float (/ 10 3)) 
;;=> 3.3333333 
(double (/ 10 3)) 
;;=> 3.333333333333333 

The quot function returns the quotient of dividing the numerator by the denominator, and the decimal point is suppressed. rem returns the remainder of dividing the numerator by the denominator:

(quot 10 3) 
;;=> 3 
(rem 10 3) 
;;=> 1 

Clojure supports big numbers, and they are Java's BigDecimal. The bigdec function casts any number to BigDecimal. The suffix M denotes BigDecimal. Though it can express very large numbers, it cannot express repeating decimals and causes an error:

(bigdec (/ 10 2)) 
;;=> 5M 
(bigdec (/ 10 3)) 
;; ArithmeticException Non-terminating decimal expansion; no exact representable decimal result.  ;; java.math.BigDecimal.divide (BigDecimal.java:1690) 

Clojure also provides large integers, clojure.lang.BigInt. It is equivalent to Java's java.math.BigInteger:

(= (bigint 10) 10N) 
;;=> true 

Using strings and characters

Clojure strings are Java's String(java.lang.String) enclosed by double quotes (""):

"Hello world ! " 
;;=> "Hello world ! " 

Clojure has good interoperability with Java, and it's easy to call Java's member methods from Clojure. In the following example, the code calls the concat method in Java's String class:

(.concat "Hello " "world !") 
;;=> "Hello world !" 

The following syntax is how to call Java's member methods from Clojure:

(.method-name object arg1 arg2 ...) 

The first argument is a dot (.) prefix followed by the method name, then the object and its arguments.

The equivalent Java code is as follows:

String str = "Hello ".concat("world !"); 

The str function is similar to the concat method, but it can take an arbitrary number of arguments:

(str "Hello " "world !" " Clojure") 
;;=> "Hello world ! Clojure" 

To examine the length of the string, use the length method or count function:

(.length "Hello world !") 
;;=> 13 

clojure.string is a built-in Clojure library to manipulate strings. Here, we show some functions in clojure.string:

(clojure.string/blank? "   ") 
;;=> true 
(clojure.string/trim "  Hello ") 
;;=> "Hello" 
(clojure.string/upper-case "clojure") 
;;=> "CLOJURE" 
(clojure.string/capitalize "clojure") 
;;=> "Clojure" 
(clojure.string/lower-case "REPL") 
;;=> "repl" 

Let's go to Clojure character type. Characters in Clojure are java.lang.Character and are preceded by a backslash (\):

\a 
;;=> \a 

The int function gets the integer value of a character. Meanwhile, char gets an integer value from a character:

(int \a) 
;;=> 97 
(char 97) 
;;=> \a 

The seq function returns a sequence of characters from a string, and str makes a string from characters:

(seq "Hello world!") 
;;=> (\H \e \l \l \o \space \w \o \r \l \d \!) 
(str \C \l \o \j \u \r \e) 
;;=> "Clojure" 

Using booleans and nil

Clojure's booleans are java.lang.Boolean, and their values are true and false:

true 
;;=> true 
false 
;;=> false 
(= 1 1) 
;;=> true 
(= 1 2) 
;;=> false 
(= "Hello" "Hello") 
;;=> true 
(= "Hello" "hello") 
;;=> false 

The not function returns true if an expression is logically false. It returns false otherwise:

(not true) 
;;=> false 
(not false) 
;;=> true 
(not= 1 2) 
;;=> true 
(not true) 
;;=> false 

The true? function returns true if the expression is true; otherwise, it returns false. The false? function returns false if the expression is true; otherwise, it returns true:

(true? (= 1 1)) 
;;=> true 
(false? (= 1 1)) 
;;=> false 

The nil function means nothing, or the absence of a value. The nil function in Clojure is almost equivalent to the null function in Java. nil is logically false in Clojure conditionals. nil is often used as a return value to indicate false:

(if nil true false) 
;;=> false 

nil is the return value used to indicate an empty sequence:

(seq []) 
;;=> nil 

nil is returned by default when a map collection looks up and can't find a given key:

(get {:a 1 :b 2} :c) 
;;=> nil 

Using symbols and keywords

The function def binds global symbols to their values. The next example shows the def binding the pi symbol to a value (3.14159265359):

(def pi 3.14159265359) 
;;=> #'user/pi 
pi 
;;=> 3.14159265359 
pi-not-bind 
;;=> CompilerException java.lang.RuntimeException: Unable to resolve symbol: 
;;    pi-not-bind in this context, compiling:(/tmp/form-init1426260352520034213.clj:1:7266) 

Keywords are similar to symbols, but keywords evaluate to themselves:

:key1 
;;=> :key1 

Keywords are used to identify things, so they are often used in Clojure's map:

(def person {:name "John McCarthy" :country "USA"}) 
;;=>#'living-clojure.core/person 

How it works...

Clojure primitive data types are mostly Java classes, but some data types are Clojure's own classes.

For numbers, Clojure's integers are java.lang.Long and floating point numbers are java.lang.Double. bigInt and ratios are clojure.lang.BigInt and clojure.lang.Ratio respectively:

(class 1) 
;;=> java.lang.Long 
(class 1.0) 
;;=> java.lang.Double 
(class (float 1.0)) 
;;=> java.lang.Float 
(class 5.5M) 
;;=> java.math.BigDecimal 
(class 1N) 
;;=> clojure.lang.BigInt 
(class (/ 10 3)) 
;;=> clojure.lang.Ratio 

Clojure's strings and characters are java.lang.String and java.lang.Character respectively:

(class "Hello world ! ") 
;;=> java.lang.String 
(class \a) 
;;=> java.lang.Character 
(class true) 

Clojure's booleans are java.lang.Boolean:

(class true) 
;;=> java.lang.Boolean 
(class false) 
;;=> java.lang.Boolean 

Clojure's keywords and symbols are Clojure's own classes:

(class :key) 
;;=> clojure.lang.Keyword 
(class (quote a)) 
;;=> clojure.lang.Symbol 
(class nil) 
;;=> nil 

There's more...

Clojure supports hexadecimal and octal notations:

0xff 
;;=> 255 
0400 
;;=> 256 

Clojure also supports flexible numeral bases. You can specify in any base with a radix from 2 to 36:

2r11111 
;;=> 31 
16rff 
;;=> 255 
8r11000 
;;=> 4608 
7r111 
;;=>57 

There are some specially named character literals, as follows:

  • \space

  • \tab

  • \newline

  • \return

  • \formfeed

  • \backspace

Unicode characters are represented by \uNNNN in Clojure, like in Java:

\u0031\u0032\u0061\u0062 
;;=> \1 
;;=> \2 
;;=> \a 
;;=> \b 

Functions in Clojure are also symbols and bind to their functional definitions. The next example shows the value of +:

+ 
;;=> #object[clojure.core$_PLUS_ 0x3c2ace8a "clojure.core$_PLUS_@3c2ace8a"] 

To evaluate symbol and return itself, use quote:

(quote pi-not-bind) 
;;=> pi-not-bind 

To use the math library in Clojure, try clojure.math.mumeric-tower. Here are the steps:

  1. Add the following dependency to project.clj:

          [org.clojure/math.numeric-tower "0.0.4"] 
    
  2. You can use expt and sqrt in the library:

          (require '[clojure.math.numeric-tower :as math]) 
          (math/expt 2 10) 
          ;;=> 1024 
          (math/sqrt 10) 
          ;;=> 3.1622776601683795