Clojure “Lisp Reloaded” Versions of LISP  Lisp is an old language with many variants      LISP is an acronym for List Processing language Lisp is.

Download Report

Transcript Clojure “Lisp Reloaded” Versions of LISP  Lisp is an old language with many variants      LISP is an acronym for List Processing language Lisp is.

Clojure
“Lisp Reloaded”
Versions of LISP

Lisp is an old language with many variants





LISP is an acronym for List Processing language
Lisp is alive and well today
Most modern versions are based on Common Lisp
Scheme is one of the major variants
Clojure is the latest in a long line of dialects

Clojure uses a new approach to concurrency, Software
Transactional Memory (STM)
2
Lisp syntax vs. Clojure syntax
3
Basic data types I

Numbers: Clojure has integers, floating point numbers, and ratios




Strings are enclosed in double quotes, and can contain escaped characters


Within a string, \n represents a newline, as usual
Character literals are written as \c to indicate the character c


Integers include decimal integers (255), octals numbers (012), hexadecimal
numbers (0xff) and radix numbers (2r1111), where the radix is an integer between
2 and 36, inclusive
Floating point numbers include standard notation (3.1416) and scientific
notation(1.35e-12).
Ratios are “fractions” such as 1/3; they are not subject to roundoff error
Since \n represents the character n, \newline is used to represent a newline
Keywords are not reserved words, but are like “atoms” in Prolog or Erlang; a
keyword begins with a colon (:foo) and stands for itself
4
Basic data types II

A list is a sequence of values enclosed in parentheses, for example,
(one 2 "buckle my shoe")

Elements of the list are separated by whitespace or commas

A list represents either data or a function call, depending on context

A vector is a sequence of values enclosed in brackets, for example,
[one 2 "buckle my shoe”]


A map or hash is a sequence of key/value pairs, enclosed in braces, for
example,
{:ace 1, :deuce 2, "trey" 3}



Elements of the vector are separated by whitespace or commas
Elements are separated by whitespace or commas
It is helpful to use commas between key/value pairs
A set is a pound sign (#) followed sequence of values enclosed in braces, for
example #{a b c}
5
Functions

The syntax to define a named function is:
(defn function_name [arguments] expressions)


The syntax of a function call is
(function_name arguments)


The value of the function is the value of the last expression evaluated
Notice that the name of the function being called is the first thing inside
the parentheses
The syntax of an anonymous function, or lambda, is
(fn [arguments] expressions)



This syntax can be used in place of a function name
Example: ((fn [lst] (first lst)) my-list) is equivalent to (first my-list)
Since functions are first-class values, this syntax is convenient for creating
a function to be used as an argument to another function
6
Sequences


Lists, vectors, maps, and sets are all “sequences,” and
many of the same operations apply
(first seq) returns the first element of seq


(rest seq) returns the seq without its first element


If the seq is empty, the empty list, (), is returned
If the seq is empty, the empty list, (), is returned
(cons value seq) returns a sequence of the same type
with the value inserted as the new first element
7
Fast and slow operations

Sequence is an interface roughly analogous to Java's Iterator:




Clojure.org describes sequences as “logical lists”





It is a small interface (a couple of methods) that can be applied to a large range of data types
Many (most?) of the common Clojure operations are defined on sequences
For example, map and reduce work across almost all data types.
The primary sequence operations are first, rest and cons
Everything else is built around these operations.
The set of cheap (constant time) operations are the same as for lists:
Add/remove/access the first element or iterate over all elements
Operations like nth and last are expensive (O(n) time) since they must
traverse the entire list.
Unlike lists, count - getting the length of a sequence - is also expensive.
8
Sequence operations

Sequence operations can be used on almost any compound type






Collections: Vector, list, map, set, struct
Strings (as char sequence)
Java arrays, collections, sets, maps, iterator, enumerable
IO streams
Producer functions: Many lazy seqs do not get their values from a backing data set,
but from a function that calculates the value when asked for.
Some collections can be used directly as sequences, others need
to be converted

The rules are somewhat different for different kinds of collections, so the simplest
general strategy is to



convert to sequence
do the processing
if you need a particular non-sequence type (like vector or array), convert the return
value back
9
Predicates


A predicate (in any computer language) is a function that
returns either “true” or “false”
In Clojure,



“false” is one of the atoms false or nil
“true” is the atom true
In addition, anything that isn’t false or nil is considered to be true


In particular, the empty list, (), is “true”
Hence, a predicate returns either false, nil, or any other
value to mean “true”

Predicates often return “true” values other than true, especially if the
returned value might be useful
10
Function calls and data

A function call is written as a list



Example: (println "Hello" "World")




The first element is the name of the function
Remaining elements are the arguments
Calls function println with arguments "Hello" and "World”
The function prints Hello World and returns nil
Data is written as atoms or lists
Example: (println "Hello" "World") is a list of three
elements

Do you see a problem here?
11
Quoting


Is (f a b) a call to f, or is it just data?
All literal data must be quoted (atoms, too)



x indicates the variable x, while (quote x) is just x
(quote (f a b)) is the list (f a b)




Exceptions include nil, true, and nil, which do not need to be quoted
quote is not a function, but a special form
The special form gets the unevaluated arguments, and is control of
when or whether to evaluate them
Special forms, unlike functions, are not first-class values
'(f a b) is a shorthand way of doing the same thing


There is just one single quote at the beginning
It quotes one expression
12
Examples

(defn my-first [x]
(first x))


user=> (my-first '(1 2 3))
1
defn my-second [lst]
(first (rest lst)))

user=> (my-second '(a b c))
b

(defn my-third
"This is a doc comment"
[lst]
(first (rest (rest lst))) )


user=> (my-third "Whatever")
\a
user=> (doc my-third)
------------------------user/my-third
([lst])
This is a doc comment
nil
13
Arithmetic




+
*
/









Returns the sum of its arguments; (+) returns 0
Subtracts the rest of the numbers from the first number
Returns the product of its arguments;(*) returns 1.
Divides the rest of the numbers into the first number
If operands are integers, result is a ratio
If only one number, returns its inverse
quot Returns the quot[ient] of integer division of the first number by the rest
of the numbers
rem remainder of dividing the first number by the second
mod Modulus of first and second number; truncates toward negative infinity
inc Returns a number one greater than its argument
dec Returns a number one less than its argument
max Returns the largest of its arguments
min Returns the smallest of its arguments
14
Numeric comparisons

=








Returns true if all arguments are equal
This is a true equality test, not an identity test
Collections are compared in a type-independent manner; for example,
(= '(1 2 3) '[1 2 3]) returns true
== Returns true if numeric arguments all have the same value, otherwise
false
not= Same as (not (= obj1 obj2))
<
Returns true if numeric arguments are in monotonically increasing order
>
Returns true if numeric arguments are in monotonically decreasing order,
otherwise false
<= Returns true if numeric arguments are in monotonically non-decreasing
order, otherwise false
>= Returns true if numeric arguments are in monotonically non-increasing
order, otherwise false
15
Conditional execution

if is a special form that takes exactly three arguments:





A predicate
An expression to evaluate if the predicate is true
An expression to evaluate if the predicate is false
Syntax: (if predicate true-branch false-branch)
Example:
(defn sum [lst]
(if (= lst ())
0
(+ (first lst) (sum (rest lst))) ) )
(defn average [lst]
(/ (sum lst) (count lst)) )
16
The problem with if

if expressions nest rather awkwardly


(defn collatz [n]
(println n)
(if (= n 1)
1
(if (= (rem n 2) 0)
(collatz (/ n 2))
(collatz (inc (* 3 n))) ) ) )
In most cases, the more general cond is preferred
17
cond

cond implements the
if...then...elseif...then...elseif...then... control structure

Like if, cond is a special form, not a function

That is, the arguments to cond are not evaluated before cond
is called; rather, cond evaluates the arguments as it pleases
18
Syntax of the cond


The syntax of the cond special form is:
(cond condition result condition result ...)
Example:


(defn pos-neg-or-zero
"Determines whether n is positive, negative, or zero"
[n]
(cond
(< n 0) "negative"
(> n 0) "positive"
:else "zero"))
The last condition, :else, is true, and reads better than the atom true
19
Rules for Recursion


Handle the base (“simplest”) cases first
Recur only with a “simpler” case



“Simpler” = more like the base case
Don’t alter global variables
Don’t look down into the recursion
20
Example: member


As an example we define member, to test membership
in a list
(defn member [a lat]
(cond
(empty? lat) false
(= a (first lat)) true
:else (member a (rest lat)) ) )

user=> (member :b '(:a :b :c))
true
21
Guidelines for recursive Clojure functions


Unless the function is trivial, use a cond
Handle the base case(s) first




Avoid having more than one base case
The base case is often testing for an empty list
Do something with the first and recur with the rest
Use tail recursion wherever possible
22
Example: union



(defn union [set1 set2]
(cond
(empty? set1) set2
(member (first set1) set2) (union (rest set1) set2)
:else (cons (first set1) (union (rest set1) set2)) ) )
This example uses the previously defined member function
It appears that, if function A calls function B, Clojure requires function B to be
defined before defining function A


Of all the languages I have used, only C and its variants make this requirement
Unless I’m missing something, this is a real step backward for Lisp dialects
23
Tests







nil?
identical?
zero?
pos?
neg?
even?
integer
odd?
integer
Returns true if x is nil, false otherwise.
Tests if 2 arguments are the same object
Returns true if num is zero, else false
Returns true if num is greater than
Returns true if num is less than zero, else false
Returns true if n is even, throws an exception if n is not an
Returns true if n is odd, throws an exception if n is not an
24
Type tests

coll?

seq?

vector?

list?

map?

set?
Returns true if x implements IPersistentCollection
Return true if x implements ISeq
Return true if x implements IPersistentVector
Returns true if x implements IPersistentList
Return true if x implements IPersistentMap
Returns true if x implements IPersistentSet
25
Content Tests



contains?
distinct?
empty?





Returns true if key is present in the given collection, else false
Returns true if no two of the arguments are =
Returns true if coll has no items - same as (not (seq coll))
Use the idiom (seq x) rather than (not (empty? x))
every?
false
not-every?
true
some
not-any?
Returns true if (pred x) is logical true for every x in collection, else
Returns false if (pred x) is logical true for every x in collection, else
Returns the first logical true value of (pred x) for any x in collection
Returns false if (pred x) is logical true for any x in collection, else true
26
I/O












*in* A java.io.Reader object representing standard input for read operations
*out* A java.io.Writer object representing standard output for print operations
*err* A java.io.Writer object representing standard error for print operations
print Prints the object(s) to the output stream that is the current value of *out*
printf Prints formatted output, as per format
println
Same as print followed by (newline)
pr
Prints the object(s) to the output stream that is the current value of *out*
prn Same as pr followed by (newline). Observes *flush-on-newline*
newline Writes a newline to the output stream that is the current value of *out*
read-line Reads the next line from stream that is the current value of *in*
slurp Reads the file into a string and returns it
spit Opposite of slurp. Opens file with writer, writes content, then closes it
27
REPL commands










(load-file filename) loads a file containing Clojure functions
*1 bound in a repl thread to the most recent value printed
*2 bound in a repl thread to the second most recent value printed
*3 bound in a repl thread to the third most recent value printed
*e bound in a repl thread to the most recent exception caught by the repl
*print-dup* When set to logical true, objects will be printed in a way that
preserves their type when read in later
*print-length* controls how many items of each collection the print
*print-level* controls how many levels deep the printer will print
*print-meta* If set to logical true, when printing an object, its metadata will
also be printed in a form that can be read back by the reader
*print-readably*
When set to logical false, strings and characters will be
printed with non-alphanumeric characters converted to the appropriate escape
sequences
28
Dealing with the REPL

Clojure’s REPL (Read-Eval-Print Loop) seems to be
very buggy



I get a lot of errors along these lines:
java.lang.Exception: Unable to resolve symbol: union
in this context (NO_SOURCE_FILE:43)
(It’s a Java exception because Clojure is compiled to the
JVM)
Here are two workarounds that seem to solve most such
problems:


Start a new Clojure shell, or
Just copy the function definition and paste it directly into the Clojure
shell
29
The End
30