天天看點

Clojure Getting Started Clojure Philosophy Common Syntax Java integration MySQL References

this page gives an overview of common closure scripting calls.

The following steps help you write your first clojure script:

1. Get Counterclockwise, the Eclipse plug-in at http://updatesite.counterclockwise.googlecode.com/hg (for more information, see Clojure's getting started page).

2. Then create a new Clojure project and a clojure file.

3. Add the following: (println "Hello, world").

4. Run as > clojure

More detailed info on Clojure syntax, see:

  • primer: http://www.moxleystratton.com/article/clojure/for-non-lisp-programmers
  • detailed quick reference: http://faustus.webatu.com/clj-quick-ref.html
  • book: http://java.ociweb.com/mark/clojure/article.html

Clojure Philosophy

Clojure is a functional programming language. It provides the tools to avoid mutable state, provides functions as first-class objects, and emphasizes recursive iteration instead of side-effect based looping. Clojure is impure, in that it doesn't force your program to be referentially transparent, and doesn't strive for 'provable' programs. The philosophy behind Clojure is that most parts of most programs should be functional, and that programs that are more functional are more robust.

The naming convention in Clojure is to use all lowercase with hyphens separating words in multi-word names, unlike the Java convention of using camelcase.

Clojure makes heavy use of lazy evaluation. This allows functions to be invoked only when their result is needed. "Lazy sequences" are collections of results that are not computed until needed. This supports the efficient creation of infinite collections.

Common Syntax

Alternatively, see the Clojure Sample Code.

Built in forms

if

: (

if

(=

2

2

) (println

"true"

) (println

"false"

))

str: (str

"Value: "

5

)

println and def:

(def msg (str

"this is four: "

4

))

(println msg) ; output:

this

is four:

4

do

: (

do

(println

"Hello."

) (println (+

4

1

)))

when: (when (>

50

(inc

4

))

(println

"Yes"

))

let: (let [color

"Red"

] (println (str

"Color is: "

color)) )

common arithmetic operations

add: (+

1

2

)

to assign the addition to another variable: (def v3 (+

1

2

))

increment: clojure data types are immutable.

(def incrementor

)

(println

"incrementor: "

incrementor);

//0

(println

"incrementor: "

(inc incrementor));

//1 but incrementor is unchanged

(println

"incrementor: "

incrementor);

//0

You need a mutable reference to data, that can change to point to a different value later. Create a ref with ref, and alter a ref with alter. The alter must be inside a transaction, a.k.a. a dosync block.

(def counter (let [count (ref

)] #(dosync (alter count inc))))

(println

"counter: "

(counter)) ;

1

(println

"counter: "

(counter)) ;

2

subtract: (-

4

2

)

multiply: (*

4

2

)

divide: (/

4

2

)

mod: (mod

4

2

)

power/roots/etc: None. Make your own function via defn.

comparisons

assignment:

(def x

2

)

is equal:

(

if

(=

2

2

) (println

"true"

) (println

"false"

))

>:

(def x

3

)

(

if

(> x

2

) (println

"true"

) (println

"false"

))

<:

(def x

1

)

(

if

(< x

2

) (println

"true"

) (println

"false"

))

>=:

(def x

2

)

(

if

(<= x

2

) (println

"true"

) (println

"false"

))

<=:

(def x

2

)

(

if

(<= x

2

) (println

"true"

) (println

"false"

))

not:

(def x

false

)

(

if

(not x ) (println

"true"

) (println

"false"

))

comment

block:

(comment  

(println

"Hello, world"

)

)

start of line (given syntactically correct line):

#_ (println

"Hello, world"

)

end of line:

(+

1

4

) ;

this

is a comment

functions

example in c: do_something_with(value1, value2)

same c function in clojure: (

do

-something-with value1 value2)

for

example, a function call in clojure: (election-year?

2007

)

define a function:

(defn election-year?

{:doc

"Returns boolean if the year is a presidential election year"

}

[year]

(zero? (rem year

4

))

)

(println (election-year?

2007

))

output:

false

empty arg function:

(defn printAll []

(sql/with-connection db

(sql/with-query-results rs [

"select * from users"

(dorun (map #(println %) rs))))

)

Lists Lists can have zero or more items, enclosed in parentheses. The list's elements are delimited with a space.
vector immutable, between []
list immutable, between ()
map immutable, between {}
sets immutable, between #{}
hash-map immutable, between ()
set

(def myHashMap (hash-map :abby

"actor"

:ben

"builder"

))

get

(println (get myHashMap :abby))

output: actor

def 

assoc 

dissoc 

merge- with 

doseq

(def myHashMap (hash-map :abby

"actor"

:ben

"builder"

))

(def newMap (assoc myHashMap :chris

"chemist"

)) ; create a

new

map and add chris

(println (get myHashMap :chris)) ; the original myHashMap hasn't changed, output: nil

(println (get newMap :chris)) ; output: chemist

(println (get newMap :abby)) ; output: actor

(def smallerMap (dissoc newMap :abby)) ; create a

new

map and removes abby

(println (get smallerMap :abby)) ; removes abby output: nil

(def mergedMap (merge-with +, smallerMap, {:abby

"accountant"

}))

(println (get mergedMap :abby)) ; output: accountant

(doseq [entry mergedMap]

(println entry)) ; output: [:chris chemist] [:ben builder] [:abby accountant]

looping In the absence of mutable local variables, looping and iteration must take a different form than in languages with built-in for or while constructs that are controlled by changing state. In functional languages looping and iteration are replaced/implemented via recursive function calls. Many such languages guarantee that function calls made in tail position do not consume stack space, and thus recursive loops utilize constant space.

(loop [i

]

(when (< i

5

)

(println i)

(recur (inc i))))

also, dorun and doseq
sequence

A Sequence is not a data structure but an interface, or view, into a data structure. A sequence can be derived from a collection. The relation between collection and sequence is similar to the relation between database table and database view.

sequence from a map:

(def myHashMap (hash-map :abby

"actor"

:ben

"builder"

))

(doseq [entry myHashMap]

(println entry))

output:

[:ben builder]

[:abby actor]

first: (first '(

1

2

3

))

content:

1

rest: (rest '(

1

2

3

))

content: (

2

3

)

cons (creates a

new

sequence by adding the first argument to the beginning of the collection that is the second argument):

(cons

1

[

2

3

])

content: (

1

2

3

)

Java integration

General:

(. (

new

java.util.Date) (toString))

Automated tests

(use 'clojure.test)

(deftest add-test

; The

"is"

macro takes a predicate, arguments to it,

; and an optional message.

(is (=

4

(+

2

2

)))

(is (=

2

(+

2

))

"adding zero doesn't change value"

))

(run-tests)

Output:

Testing automatedTests

Ran

1

tests containing

2

assertions.

failures,

errors.

More clojure test examples. More info on clojure tests.

Java integration

General

(. (

new

java.util.Date) (toString))

Static methods

(println (. Boolean (valueOf

"true"

)))

Class and fields

(. Integer MAX_VALUE)

Import

(

import

'(java.io FileReader))

(

new

FileReader

"source.txt"

)

Create instance

(

import

'java.util.Date)

(def today (

new

Date))

; or

(def today (Date.))

Call instance methods

(

import

'java.util.Date)

(def today (Date.))

(let [today (Date.)]

(.getTime today)

(.getTime today) ; called again to show calling within the let

)

Call Java static methods

(System/currentTimeMillis)

Chaining

(..

(Calendar/getInstance)

(get (Calendar/MINUTE)))

Implementing interfaces and extending classes (use the reify macro):

(def my-obj

(reify Runnable

(run [

this

]

(println

"running ..."

)

)

)

)

(.run my-obj)

MySQL

(Alternatively, see the entire clojure MySQL demo code.)

(ns mySQLTutorial

(:require [clojure.contrib.sql :as sql]))

(def db {:classname

"com.mysql.jdbc.Driver"

:subprotocol

"mysql"

:subname

"//localhost:3306/dummy"

:user

"duser"

:password

"dpass"

})

(defn create-users []

(sql/create-table

:people

[:id :integer

"PRIMARY KEY"

"AUTO_INCREMENT"

]

[:fname

"varchar(25)"

]

[:lname

"varchar(25)"

]

[:town

"varchar(25)"

]

)

)

(defn drop-users []

(sql/drop-table :users))

;;;;;;;;;inserting data is accomplished via insert-values function;;;;;;;;

(defn insert-user [fname lname town]

(sql/insert-values :people [:fname :lname :town] [fname lname town]))

;;;;;;;;;;;;to update a record

(defn update-person [id attribute-map]

(sql/update-values :people [

"id=?"

id] attribute-map))

;;;;;;;;;;delete a record

(defn delete-person [id]

(sql/with-connection db

(sql/delete-rows :people [

"id=?"

id])))

Commands

With clojure you can use all the familiar MySQL commands. In the following examples, the commands are wrapped into a def which binds the MySQL command to

'statement'

. Then the command is  processed with:  (sql/with-query-results rs [statement]

(defn printAll [table]

(sql/with-connection db

(def statement (str

"select * from "

table ))

(sql/with-query-results rs [statement]

(dorun (map #(println %) rs))))

)

;;;;;;;;;;search

for

all who match a last name

(defn selectLastname [lastName]

(println

"******************"

)

(sql/with-connection db

(def statement (str

"select * from people where lname=\""

lastName

"\""

))

(sql/with-query-results rs [statement]

(dorun (map #(println %) rs))))

)

;;;;;;;;;;;;;call a function

(sql/with-connection db

(insert-user

"40"

"Denver"

"Abby"

"Smith"

)

Join

Do a join between two tables (people and alumni) joining on last name

for

a specific last name where the tables are:

mysql> select * from people;

+---+--------+-------+-----------+

| id  | fname  | lname  | town        |

+---+--------+-------+-----------+

1

| Abby    | Smith  | Allenwood |

2

| Ben      | Brown | Boston      |

3

| Sandy   | Brown | Chester    |

4

| Charlie  | Brown | Dover       |

+----+-------+-------+-----------+

second table:

mysql> select * from alumni;

+---+-----+--------+-------+-------+

| id  | age | college  | fname | lname |

+---+-----+--------+-------+-------+

1

|

30

| Bacon   | Sandy | Brown |

3

|

21

| Cherry  | Scott  | Brown |

4

|

40

| Denver  | Abby  | Smith  |

+---+-----+--------+-------+-------+

(defn selectLastNameTwoTables [table1 table2 lastName]

(sql/with-connection db

(def statement (str

"select "

table1

".lname, "

table1

".fname, "

table1

".town, "

table2

".college, "

table2

".age from "

table1

", "

table2

" where "

table1

".lname = "

table2

".lname and "

table1

".fname = "

table2

".fname and "

table1

".lname = '"

lastName

"'"

))

(sql/with-query-results rs [statement]

(dorun (map #(println %) rs))))

)

(selectLastNameTwoTables

"people"

"alumni"

"Brown"

)

output:

{:lname Brown, :fname Sandy, :town Chester, :college Bacon, :age

30

}

References

http://clojure.blip.tv/?sort=custom;date=;view=archive;user=clojure;nsfw=dc;s=posts;page=1