clojure从零开始(三)

1.语法形式

(operator operand1 operand2 ... operandn)

(操作符 参数1 参数2  ....)e.g.(+ 1 2 3)

2.几个我经常用的Control Flow

2.1 if

if一般的结构是:

(if boolean-form
  then-form
  optional-else-form)
下面是一个例子:
(if (= 2 2)
  "OK"
  "ERROR")
; => "OK"

注意每一个分支,if只能有一种形式。这是大多数语言不同。例如,在Ruby中,可以这样写:

if true
  doer.do_thing(1)
  doer.do_thing(2)
else
  other_doer.do_thing(1)
  other_doer.do_thing(2)
end
为了解决这个明显的限制,我们用do来操作: 

2.2 do

do可以让你“wrap up”多种形式。例如REPL:

(if true
  (do (println "Success!")
      "OK")
  (do (println "Failure :(")
      "ERROR"))
; => Success!
; => "OK"
在这种情况下,Success!被印在REPL和“OK"返回为整个if表达式的值。 

2.3 when

当操作者就像是if和do的一个组合,做,但没有else的形式用when。例如:

(when true
  (println "Success!")
  "abra cadabra")
; => Success!
; => "abra cadabra"

用when的时候即当某个条件为真时,你想要做多个事情;当条件为假时使用的,不想做任何事情。

3 def 

使用def将名字绑定到Clojure中的值:

(def failed-protagonist-names
  ["Larry Potter"
   "Doreen the Explorer"
   "The Incredible Bulk"])

在这种情况下,你要绑定的名称 failed-protagonist-names 包含三个字符串的向量。请注意,我使用术语“绑定”,而在其他语言你会说,赋值给一个变量。例如,在Ruby中,你可能会执行多个任务给一个变量,以“build up”它的值:

severity = :mild
error_message = "OH GOD! IT'S A DISASTER! WE'RE "
if severity == :mild
  error_message = error_message + "MILDLY INCONVENIENCED!"
else
  error_message = error_message + "DOOOOOOOMED!"
end
等效的Clojure是:

(def severity :mild)
(def error-message "OH GOD! IT'S A DISASTER! WE'RE ")
(if (= severity :mild)
  (def error-message (str error-message "MILDLY INCONVENIENCED!"))
  (def error-message (str error-message "DOOOOOOOMED!")))
然而,这是非常糟糕的Clojure。现在,你应该把def作为它定义的常量。But,you'll learn how to work with this apparent limitation by coding in the functional style later.

3.数据结构 

Clojure的带有很多数据结构,我们会使用其中的一大部分。所有Clojure的数据结构都是不可变的,这意味着你不能在任何地方更改它们。有没有Clojure的等值以下的Ruby:

failed_protagonist_names = [
  "Larry Potter",
  "Doreen the Explorer",
  "The Incredible Bulk"
]
failed_protagonist_names[0] = "Gary Potter"
failed_protagonist_names
# => [
# "Gary Potter",
# "Doreen the Explorer",
# "The Incredible Bulk"
# ]
接下来,是更多关于Clojure的如何实现

3.1 nil, true, false, Truthiness, Equality

Clojure中有true和false值。nil是用来表示在Clojure的“no value”。您可以检查某个值是否为nil用nil? 
(nil? 1)
; => false

(nil? nil)
; => true
nil和false用于表示逻辑falsiness,而所有其他值在逻辑上是truth。 =是相等运算符:

(= 1 1)
; => true

(= nil nil)
; => true

(= 1 2)
; => false

3.2. Numbers

Clojure中有相当复杂的数字支持。我不打算花太多时间纠缠于无聊的技术细节(like coercion and contagion)),因为这些你会在做事中获得。如果你有兴趣,请查看http://clojure.org/data_structures#Data Structures-Numbers。

93
1.2
1/5
93  integer;1.2 float;1/5 ratio

3.3 string

Clojure中只允许“ ”来界定字符串。比如‘cpp’,就不是一个有效的字符串。Clojure没有字符串插值。它仅允许通过函数级联str:

(def name "Chewbacca")
(str "\"Uggllglglglglglglglll\" - " name)
; => "Uggllglglglglglglglll" - Chewbacca
3.4 Maps

maps在其他语言是类似于dictionaries or hashes。他们一些值联系一些值的一种方式。下面是例子:

;; An empty map
{}

;; ":a", ":b", ":c" are keywords and we'll cover them in the next section
{:a 1
 :b "boring example"
 :c []}

;; Associate "string-key" with the "plus" function
{"string-key" +}

;; Maps can be nested
{:name {:first "John" :middle "Jacob" :last "Jingleheimerschmidt"}}
请注意,maps的值可以是任何类型的。string,number,map,vector,甚至是 function 。 


你可以用get函数在maps上查找值:

(get {:a 0 :b 1} :b)
; => 1

(get {:a 0 :b {:c "ho hum"}} :b)
; => {:c "ho hum"}

若果key查找不到,get将返回nil,但是你可以给一个默认值

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

(get {:a 0 :b 1} :c "UNICORNS")
; => "UNICORNS"
该get-in函数可以让你在嵌套的maps里查找value:

(get-in {:a 0 :b {:c "ho hum"}} [:b :c])
; => "ho hum"

[:b :c] 是一个 vector

另一种方法来查找一个值的映射是将maps看做一个函数,用key作为其参数:

({:name "The Human Coffee Pot"} :name)
; => "The Human Coffee Pot"
 3.5 Keywords

一般用做map中的key

:a
:rumplestiltsken
:34
:_?
关键字可以作为函数来查找对应在数据结构中的值。例如:

;; Look up :a in map
(:a {:a 1 :b 2 :c 3})
; => 1

;; This is equivalent to:
(get {:a 1 :b 2 :c 3} :a)
; => 1

;; Provide a default value, just like get:
(:d {:a 1 :b 2 :c 3} "FAERIES")
; => "FAERIES
可以用hash-map来创建一个map

(hash-map :a 1 :b 2)
; => {:a 1 :b 2}
也可以创建sorted maps

3.6 Vectors

Vectors类似于array,都是0-indexed集合

;; Here's a vector literal
[3 2 1]

;; Here we're returning an element of a vector
(get [3 2 1] 0)
; => 3

;; Another example of getting by index. Notice as well that vector
;; elements can be of any type and you can mix types.
(get ["a" {:name "Pugsley Winterbottom"} "c"] 1)
; => {:name "Pugsley Winterbottom"}
就像在maps中查找值一样,我们同样使用get函数取值,接下来的章节解释了为什么这样做。 

创建vector

(vector "creepy" "full" "moon")
; => ["creepy" "full" "moon"]
添加元素会添加到vector最后

(conj [1 2 3] 4)
; => [1 2 3 4]
3.7 Lists

Lists类似于vectors,他们都是值得线性集合,但是也有一些差别,不能用get检索列表(list)

;; Here's a list - note the preceding single quote
'(1 2 3 4)
; => (1 2 3 4)
;; Notice that the REPL prints the list without a quote. This is OK,
;; and it'll be explained later.


;; Doesn't work for lists
(get '(100 200 300 400) 0)

;; This works but has different performance characteristics which we
;; don't care about right now.
(nth '(100 200 300 400) 3)
; => 400
创建list

(list 1 2 3 4)
; => (1 2 3 4)
添加元素的话,会添加到list的头部

(conj '(1 2 3) 4)
; => (4 1 2 3)
何时使用list,何时使用vector,建议最好用vector

3.8 Sets

sets是唯一值的集合

;; Literal notation
#{"hannah montanna" "miley cyrus" 20 45}

;; If you try to add :b to a set which already contains :b,
;; the set still only has one :b
(conj #{:a :b} :b)
; => #{:a :b}

;; You can check whether a value exists in a set
(get #{:a :b} :a)
; => :a

(:a #{:a :b})
; => :a

(get #{:a :b} "hannah montanna")
; => nil

可以使用set函数创建套现有 vectors 和lists。一个不明显的用途是可以检查一个元素是否在一个集合中存在

(set [3 3 3 4 4])
; => #{3 4}

;; 3 exists in vector
(get (set [3 3 3 4 4]) 3)
; => 3

;; but 5 doesn't
(get (set [3 3 3 4 4]) 5)
; => nil
可以创建hash sets 和sorted sets

(hash-set 1 1 3 1 2)
; => #{1 2 3}

(sorted-set :b :a :c)
; => #{:a :b :c}

3.9. Symbols and Naming

symbols通常用来指某物标识符。例如:

(def failed-movie-titles ["Gone With the Moving Air" "Swellfellas"])

def用名为failed-movie-titles的symbol 连接值[“Gone With the Moving Air”,“Swellfellas”]

Lisp,允许操纵多种symbols作为data,当开始用macros(宏)工作时,我们会看到很多例子。函数可以返回symbols,也可以把它们作为参数:

;; Identity returns its argument
(identity 'test)
; => test

3.10. Quoting

也许你已经注意到了单引号'。这被称为“quoting”。

给Clojure的一个symbol返回“object”是指:

failed-protagonist-names
; => ["Larry Potter" "Doreen the Explorer" "The Incredible Bulk"]

(first failed-protagonist-names)
; => "Larry Potter"

引用一个symbol就是告诉Clojure中使用的symbol本身作为一种 data structure,而不是symbol引用的object:

'failed-protagonist-names
; => failed-protagonist-names

(eval 'failed-protagonist-names)
; => ["Larry Potter" "Doreen the Explorer" "The Incredible Bulk"]

(first 'failed-protagonist-names)
; => Throws exception!

(first ['failed-protagonist-names 'failed-antagonist-names])
; => failed-protagonist-names
You can also like lists, maps, and vectors. All within the collection will be unevaluated:

您还可以quote collectionslists, maps, and vectors.symbols时在集合中的所有符号都会被不计算:

'(failed-protagonist-names 0 1)
; => (failed-protagonist-names 0 1)

(first '(failed-protagonist-names 0 1))
; => failed-protagonist-names

(second '(failed-protagonist-names 0 1))
; => 0

3.11. Simplicity

注意,这种数据结构并不包括如何创建new types or classes的描述。这是因为Clojure的强调简洁,“基本”数据结构第一,函数是头等公民。 

























你可能感兴趣的:(clojure从零开始(三))