Clojure

#Clojure

在Clojure中,任何函数调用都需要用括号将其包起来。括号里 的第一个元素是函数名,剩下的是参数。

user=> ( println  "Give Me Some Clojure!")
Give Me Some Clojure!
nil
user=> (-1)
ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn  user/eval1170 (form-init1159783663733578044.clj:1)
user=> ( - 1 )
-1
user=> ( - 0 1 )
-1
user=> ( + 0 1 )
1
user=> ( * 0 1 )
0
user=> ( / 0 1 )
0
user=> ( / 0.0 1 )
0.0
user=> ( class ( / 1 3 ) )
clojure.lang.Ratio
user=> ( < 0.0 1 )
true
user=> ( > 0.0 1 )
false
  • 字符串和字符

字符并不是长度为1的字符串

user=> ( = "a" \a )
false
user=> ( = (str  \a) "a" )
true
user=>
  • 布尔值和表达式
user=> (first())
nil
user=> (if 0 ( println "true"))
true
nil
user=> (if nil ( println "true"))
nil
user=> (if "" ( println "true"))
true
nil
user=>

0和""都是true,但nil不是.

Lisp允许把数据当作代码。 这样我们可以把代码分成多行,让它看起来更漂亮些:

user=> (if ( < 1 2)
  #_=> ( println "False it is not."))
False it is not.
nil
user=>
  • 列表、映射表、集合以及向量
  1. 列表
user=> ( list 1 2 4)
(1 2 4)
user=> `( 1 2 4)
(1 2 4)
user=> (first `(:r2d2 :c3pro))
:r2d2
user=> (last `(:r2d2 :c3pro))
:c3pro
user=> (rest `(:r2d2 :c3pro :e4))
(:c3pro :e4)
user=> (cons :battle-droid `(:r2d2 :c3pro :e4))
(:battle-droid :r2d2 :c3pro :e4)
user=>

2.向量

向量是为随机访问优化的,用方括号括起来。

列表作代码,向量作数据。可以像下面这样获取各种元素:

user=> [ :hutt :wookie :ework]
[:hutt :wookie :ework]
user=> (first [ :hutt :wookie :ework])
:hutt
user=> (nth [ :hutt :wookie :ework] 2 )
:ework
user=> (nth [ :hutt :wookie :ework] 0 )
:hutt
user=> (last [ :hutt :wookie :ework]  )
:ework
user=> ( [ :hutt :wookie :ework] 2)
:ework
user=>

向量也是函数,取下标为参数。可以合并两个向量:

user=> (concat [:hello, :word] [ :hutt :wookie :ework] )
(:hello :word :hutt :wookie :ework)
user=>

向量必须使用:来定义元素。

repl打印出来的不是向量而是列表。许多返回集合的函数都使用了称为序列的 Clojure抽象,在repl 中以列表的形式展现。

列表和向量都是有序集合。

  • Set
user=> #{:x-wing :y-wing :tie-fighter}
#{:y-wing :tie-fighter :x-wing}
user=> (def spacecraft #{:x-wing :y-wing :tie-fighter})
#'user/spacecraft
user=> (count spacecraft)
3
user=> (sort spacecraft)
(:tie-fighter :x-wing :y-wing)
user=> (sorted-set spacecraft)
sorted-set      sorted-set-by
user=> (sorted-set 231)
#{231}
user=> (sorted-set 2 3 1)
#{1 2 3}
user=> (clojure.set/union spacecraft #{2 3 1})
#{1 :y-wing :tie-fighter 3 :x-wing 2}
user=> (clojure.set/difference #{1 2 3} #{2})
#{1 3}
user=> (#{:jar-jar :chewbacca} :luke)
nil
user=> (#{:jar-jar :chewbacca} :jar-jar)
:jar-jar
user=>

set也是函数

  • 映射表
user=> (def mentors {:darth-vader "obi wan", :luke "yoda"})
#'user/mentors
user=> (mentors :luke)
"yoda"

映射表本身也是函数。关键词同样也是函数。

user=> (:luke mentors)
"yoda"
user=>

对于一个散列值同时出现在两个映射表中的情况,还可以声明一个操作符

user=> ( merge {:y-wing 2, :x-wing 4} {:tie-fighter 2})
{:tie-fighter 2, :y-wing 2, :x-wing 4}
user=> ( merge-with + {:y-wing 2, :x-wing 4} {:tie-fighter 2, :x-wing 3})
{:tie-fighter 2, :y-wing 2, :x-wing 7}
user=>

排序表

user=> (sorted-map 1 :one, 3 :three, 2 :two)
{1 :one, 2 :two, 3 :three}
user=>
  • 函数

定义函数的最简形式是 (defn [params] body) 。我们定义了一个没有参数的函数 force-it 。
这个函数只是把两个字符串拼接起来。调用方式和其他任何函数一样:

user=> (defn force-it [] (str "Use the force, " "Luke."))
#'user/force-it
user=> (force-it)
"Use the force, Luke."
user=> 

如果愿意的话,还可以加上描述函数的字符串:

user=> (defn force-it 
"The first function a young Jedi needs"
[]
(str "Use the force, " "Luke"))
#'user/force-it
user=> 
user=> (defn force-it 
"The first function a young Jedi needs"
[]
(str "Use the force, " "Luke"))
#'user/force-it
user=> (doc force-it)
-------------------------
user/force-it
([])
  The first function a young Jedi needs
nil
user=> (defn force-it 
"This first function a young Jedi needs"
[jedi]
(str "Use the force," jedi))
#'user/force-it
user=> (force-it "Luke")
"Use the force,Luke"
user=> (doc str)
-------------------------
clojure.core/str
([] [x] [x & ys])
  With no args, returns the empty string. With one arg x, returns
  x.toString().  (str nil) returns the empty string. With more than
  one arg, returns the concatenation of the str values of the args.
nil
user=> 

绑定

user=> (def line [[0 0] [10 20]])
#'user/line
user=> line
[[0 0] [10 20]]
user=> (defn line-end [ln] ( last ln))
#'user/line-end
user=> (line-end line)
[10 20]
user=> (defn line-end [[_ second]] second)
#'user/line-end
user=> (line-end line)
[10 20]
user=> 

这里用到一个概念叫解构(destructuring)。即将一个数据结构拆解开来并从中提取出需要的
部分。下面我们来详细探讨绑定。对于 [[_ second]] ,外层方括号用来定义形参向量,内层方
括号指明将要绑定的是列表的元素还是向量的元素。 _ 和 second 分别表示单独的元素,通常
用 _ (下划线)表示被忽略的参数。也就是说,这个函数的形参分别是: _ 对应第一个实参中的第
一个元素, second 对应第一个实参中的第二个元素。
绑定可以嵌套。比方说有个井字棋(又叫一字棋, tic-tac-toe)棋盘。现在我们想返回棋盘
正中间那个方框里的值。假设棋盘表示为每行三子共三行,像下面这样:

user=> (def borad [ [:x :o :x] [:o :x :o] [:o :x :o] ] )
#'user/borad
user=> (defn center [ [ _ [ _ c _] _ ] ] c )
#'user/center
user=> (center borad )
:x
user=> 

可以利用 let 函数对 center 函数的调用方隐藏解构,let语句都能将一个变量绑定到一个值上:

user=> (def person {:name "Jabba" :profession "Gangster"})
#'user/person
user=> (let [{name :name} person] (str "The person's name is " name ))
"The person's name is Jabba"

解构映射表:

user=> borad 
[[:x :o :x] [:o :x :o] [:o :x :o]]
user=> (defn center [borad ]
( let [[ _ [ _ _ c ]] borad ] c ))
#'user/center
user=> (center borad )
:o
user=> 

同时处理映射表和向量:

user=> (def villains [{ :name "Godzilla" :size "big"} {:name "Ebola" :size "small"}])
#'user/villains
user=> (let [[ _ {name :name}] villains ] ( str "Name of the second villian:" name))
"Name of the second villian:Ebola"
user=> 

匿名函数

user=> (map (fn [w] ( * 2 (count w))) people)
(6 16)
user=> (map #( * 2 (count % ) ) people )
(6 16)
user=> 

在这个简写形式中,#定义了一个匿名函数,而%则被绑定到序列中的每个元素上。#叫做宏读取器(reader macro)。

  • Yoda 与原力

用loop 和 recure 递归

user=> (defn size [v] 
(if ( empty? v)
0
(inc ( size ( rest v )))))
#'user/size
user=> (size [1 2 3 4])
4
user=> ( loop [ x  1 ] x )
1
user=> ( defn size [ v ] 
( loop [ l v , c 0 ]
(if ( empty? l )
c
(recur (rest l ) ( inc c )))))
#'user/size
user=> (size [ 1 2 4])
3
user=> 

序列

序列是与具体实现无关的抽象层,囊括了Clojure系统里各式的容器。序列封装了所有Clojure集合(set、映射表、向量,等等)、字符串,甚至包括文件系统结构(流、目录)。它们也为Java容器提供了公共抽象,包括Java集合、数组以及字符串。一般来说,只要支持函数 first 、 rest和 cons ,就可以用序列封装起来。

使用向量时,Clojure有时会在命令行中返回列表:

user=> [ 1 2 3  ] 
[1 2 3]
user=> (rest [ 1 2 ])
(2)
user=> 

注意,开始用的是向量,但结果并不是列表。repl实际上是返回序列作为响应。这意味着所有集合都能以一种通用方式对待。让我们来看看公共序列函数库,它的丰富与强大,用一节的内容难以描述,但我会试着让你了解都有哪些可用的函数,下面简单介绍一下用于修改、测试和创建序列的函数。

测试

user=> ( every? number? [ 1 2 4 0 :four])
false
user=> ( some nil? [ 1 2 nil] )
true
user=> ( not-every? odd? [ 1 3 5 ])
false
user=> (not-any? number? [:one :two :three])
true
user=> 

修改序列

user=> ( every? number? [ 1 2 4 0 :four])
false
user=> ( some nil? [ 1 2 nil] )
true
user=> ( not-every? odd? [ 1 3 5 ])
false
user=> (not-any? number? [:one :two :three])
true
user=> (def words [ "luke" "chewie" "han" "lando"])
#'user/words
user=> (filter (fn [word] ( > (count word) 4 )) words )
("chewie" "lando")
user=> (map ( fn [x] ( * x x)) [ 1 2 3 34 4])
(1 4 9 1156 16)
user=> (def colors [ "red" "blue"])
#'user/colors
user=> (def toys ["block" "car"])
#'user/toys
user=> (for [x colors ] (str "I like "  x ))
("I like red" "I like blue")
user=> (for [x colors, y toys ] (str "I like "  x  " " y "s"))
("I like red blocks" "I like red cars" "I like blue blocks" "I like blue cars")
user=> (defn small-word? [w] ( < (count w) 4 ))
#'user/small-word?
user=> (for [ x colors , y toys , :when (small-word? y)] 
( str "I like" x " " y "s"))
("I likered cars" "I likeblue cars")
user=> (reduce + [ 1 2 3 4] )
10
user=> (reduce * [ 1 2 3 4 5])
120
user=> (sort [ 3 1 2 34])
(1 2 3 34) 
user=> (defn abs [x] (if ( < x 0) ( - x ) x )) 
#'user/abs
user=> (sort-by abs [ -1 -4 3 2 ])
(-1 2 3 -4)

延迟计算

1.用range 创建有穷序列

user=> (range 1 10 )
(1 2 3 4 5 6 7 8 9)
user=> ( range 1 10 3)
(1 4 7)
user=> (range  10 )
(0 1 2 3 4 5 6 7 8 9)
user=> 

2.无穷序列和 take

user=> (take 3 (repeat "Use the Force, Luke"))
("Use the Force, Luke" "Use the Force, Luke" "Use the Force, Luke")
user=> (take 5 (cycle [:lather :rinse :repeat]))
(:lather :rinse :repeat :lather :rinse)
user=> (take 5 (drop 2 ( cycle [:lather :rinse :repeat ])))
(:repeat :lather :rinse :repeat :lather)
user=> ( ->> [:lather :rinse :repeat ] ( cycle ) ( drop 2 ) ( take 5 ))
(:repeat :lather :rinse :repeat :lather)
user=> (take 5 (interpose :and (cycle [:lather :rinse :repeat ])))
(:lather :and :rinse :and :repeat)
user=> (take 20 (interleave (cycle (range 2)) (cycle (range 3))))
(0 0 1 1 0 2 1 0 0 1 1 2 0 0 1 1 0 2 1 0)
user=> (take 5 ( iterate inc 1))
(1 2 3 4 5)
user=> (take 5 (iterate dec 0))
(0 -1 -2 -3 -4)

user=> (defn fib-pair [[a b]] [b (+ a b)])
#'user/fib-pair
user=> (fib-pair [3 5])
[5 8]
user=> (iterate fib-pair [1 1]))
([1 1] [1 2] [2 3] [3 5] [5 8] [8 13] [13 21] [21 34] [34 55] [55 89] [89 144] [144 233] [233 377] [377 610] [610 987] [987 1597] [1597 2584] [2584 4181] [4181 6765] [6765 10946] [10946 17711] [17711 28657] [28657 46368] [46368 75025] [75025 121393] [121393 196418] [196418 317811] [317811 514229] [514229 832040] [832040 1346269] [1346269 2178309] [2178309 3524578] [3524578 5702887] [5702887 9227465] [9227465 14930352] [14930352 24157817] [24157817 39088169] [39088169 63245986] [63245986 102334155] [102334155 165580141] [165580141 267914296] [267914296 433494437] [433494437 701408733] [701408733 1134903170] [1134903170 1836311903] [1836311903 2971215073] [2971215073 4807526976] [4807526976 7778742049] [7778742049 12586269025] [12586269025 20365011074] [20365011074 32951280099] [32951280099 53316291173] [53316291173 86267571272] [86267571272 139583862445] [139583862445 225851433717] [225851433717 365435296162] [365435296162 591286729879] [591286729879 956722026041] [956722026041 1548008755920] [1548008755920 2504730781961] [2504730781961 4052739537881] [4052739537881 6557470319842] [6557470319842 10610209857723] [10610209857723 17167680177565] [17167680177565 27777890035288] [27777890035288 44945570212853] [44945570212853 72723460248141] [72723460248141 117669030460994] [117669030460994 190392490709135] [190392490709135 308061521170129] [308061521170129 498454011879264] [498454011879264 806515533049393] [806515533049393 1304969544928657] [1304969544928657 2111485077978050] [2111485077978050 3416454622906707] [3416454622906707 5527939700884757] [5527939700884757 8944394323791464] [8944394323791464 14472334024676221] [14472334024676221 23416728348467685] [23416728348467685 37889062373143906] [37889062373143906 61305790721611591] [61305790721611591 99194853094755497] [99194853094755497 160500643816367088] [160500643816367088 259695496911122585] [259695496911122585 420196140727489673] [420196140727489673 679891637638612258] [679891637638612258 1100087778366101931] [1100087778366101931 1779979416004714189] [1779979416004714189 2880067194370816120] [2880067194370816120 4660046610375530309] ArithmeticException integer overflow  clojure.lang.Numbers.throwIntOverflow (Numbers.java:1374)
RuntimeException Unmatched delimiter: )  clojure.lang.Util.runtimeException (Util.java:156)
user=> (map
first 
(iterate fib-pair [1 1]))
(1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946 17711 28657 46368 75025 121393 196418 317811 514229 832040 1346269 2178309 3524578 5702887 9227465 14930352 24157817 39088169 63245986 102334155 165580141 267914296 433494437 701408733 1134903170 1836311903 2971215073 4807526976 7778742049 12586269025 20365011074 32951280099 53316291173 86267571272 139583862445 225851433717 365435296162 591286729879 956722026041 1548008755920 2504730781961 4052739537881 6557470319842 10610209857723 17167680177565 27777890035288 44945570212853 72723460248141 117669030460994 190392490709135 308061521170129 498454011879264 806515533049393 1304969544928657 2111485077978050 3416454622906707 5527939700884757 8944394323791464 14472334024676221 23416728348467685 37889062373143906 61305790721611591 99194853094755497 160500643816367088 259695496911122585 420196140727489673 679891637638612258 1100087778366101931 1779979416004714189 2880067194370816120 ArithmeticException integer overflow  clojure.lang.Numbers.throwIntOverflow (Numbers.java:1374)
user=> 

defrecord 和protocol*

Clojure程序的执行分为两个阶段。宏展开(macro expansion)阶段将语言里的所有宏翻译成
其展开形式。你可以用命令 macroexpand 观察宏展开。我们已经用过几个宏了,它们都叫做宏读
取器。分号( ; )表示注释,单引号( ' )表示引用,而数学符号( # )则表示匿名函数。为了避
免早于预期执行,在想展开的表达式前面加上一个引号:

user=> (macroexpand '' something-we-do-not-want-interpreted)
(quote something-we-do-not-want-interpreted)
user=> (macroexpand '#(count %))
(fn* [p1__71#] (count p1__71#))
user=> 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值