Clojure语法小结

内容来源 

1、fn: 
fn是一个宏,   用于定义一个简单的函数

2、简短的函数可以使用#(),%表示唯一的参数;%1、%2 ..表示第1、2、..个参数;%&表示所有参数

3、defn: 
defn 宏用来定义一个函数。它的参数包括一个函数名字,一个可选的注释字符串,参数列表,然后一个方法体。而函数的返回值则是方法体里面最后一个表达式的值。所有的函数都会返回一个值, 只是有的返回的值是nil。
  1. user=> (defn f1 [] "hello");定义无参函数  
  2. #'user/f1  
  3. user=> (f1)  
  4. "hello"  

4、 defn-:  
defn-与defn功能一致,都是用于定义函数的,但是defn-定义的函数作用域是私有的,而defn定义的函数是公有的
调用需要使用命名空间
           (defnk f [:b 10] (inc b)) 
和defn的区别在于可以为参数指定默认值,实际调用的时候如果不传参数,会使用默认值进行计算,否则采用传入的参数
(f) -> 11
(f :b 100) -> 101

5、 组合函数comp:
形如: 
Java代码   收藏代码
  1. ((comp f1 f2 .. fn) arg1 arg2 .. argn)  

就是对参数从右到左组合执行所有函数,可以转变为: 
Java代码  
  1. (f1 (f2 (.. (fn arg1 arg2 .. argn))))  

6、 偏函数partial:  
形如: 
Java代码  
  1. ((partial  f  arg1 arg2 .. argn)  arga argb .. argz)  

就是执行: 
(f  arg1 arg2 .. argn  arga argb .. argz) 
注意:偏函数的第一个参数是一个函数,后面至少有1个其他参数 
partial函数称为“偏函数”或者“部分完整函数”,因为它是不完整的,定义也用def而不是defn。 

7、 constantly函数:  
constantly函数接受一个参数x,并返回一个变参函数,该变参函数无论参数是什么,都返回这个x值。

8、 二、函数调用  
->: 
宏-> 我们也称为 “thread” 宏, 它本质上是调用一系列的函数,前一个函数的返回值作为后一个函数的参数,返回最后一次函数调用的值. 比如下面两行代码的作用是一样的: 
Java代码  
  1. user=>(first (.split (.replace (.toUpperCase "a b c d""A" "X"" "))  
  2. user=>"X"   
  3. user=> (-> "a b c d" .toUpperCase (.replace "A" "X") (.split " ") first)  
  4. user=>"X"   

9、->>: 
后面的函数迭代使用之前的函数结果作为最后一个参数,返回最后一次函数调用的值 
分下下面两个语句: 
Java代码  
  1. (-> 10 (/ 3)) ; 10/3  10作为/函数第一个参数  
  2. (->> 10 (/ 3)) ; 3/10  10作为/函数最后一个参数  

10、 eval:  
eval解析表达式数据结构(不是字符串),并返回结果。 

11、 apply函数:  
apply 把给定的集合里面的所有元素一次性地给指定的函数作为参数调用,然后返回这个函数的返回值。可以把apply看作是SQL里面的聚合函数  ,如下: 
Java代码  
  1. user=> (apply + [1 2 3 4])  
  2. 10  

12、 三、函数检查  
fn?: 
fn?用于检查给定的参数是否为函数,是返回true,否则返回false,如: 
Java代码  
  1. user=> (fn? #("test"))  
  2. true  
  3. user=> (fn? +)  
  4. true  
  5. user=> (fn? 1)  
  6. false  

13、 & varparam
相当于java中的可变参数, eg (defmacro defserverfn [name & body] ...), body表示其余的一个或者多个参数。

14、(list 1 2 3)
(1 2 3) 创建一个新列表。

15、unquote
`(1 2 ~(list 3 4))   =>  (1 2 (3 4)) 对表达进行evaluate操作。

16、 unquote-splice
`(1 2   ~@(list  3 4))   =>  (1 2 3 4) 对表达式进行evaluate操作,去掉操作后的括号。

17、'(1 2 3)
quote,原文显示列表,不对列表进行evaluate操作。

18、 #(operator %1 %2 %3 %4 %5)

(map #(+ % 3) [2 4 7]) ; -> (5 7 10) 创建匿名函数。
将函数一次应用于指定列表数据中的每一个数据,函数是源,数据是标的,类似java在一个数据集上使用迭代器循环操作。

19、 (apply + [2 4 7]); -> 13
把给定的集合里面的所有元素一次性地给指定的函数作为参数调用,然后返回这个函数的返回值,数据是源,函数是标的。 与map的区别就是map返回的还是一个集合,而apply返回的是一个元素, 可以把apply看作是SQL里面的聚合函数。

20、  (let [a 1 b 2] (+ a b))

symbol binding. make a=1 and b=2 , then compute a+b, and finally print the result。

21、 prefix#

在宏中使用,auto-gensym,在宏编译时产生唯一的symbol名字,防止命名冲突。

22、 (doseq [x [1 2 3] y [1 2 3]] (prn (* x y)))

将参数x, y在各自指定的数据集上进行笛卡尔积混排后,按照指定函数进行运算,返回结果列表,类似java中的多重for循环。

23、 (assoc {:key1 "old value1" :key2 "value2"} :key1 "value1" :key3 "value3")  ->  {:key3 "value3", :key2 "value2", :key1 "value1"}

将原始map中指定的key替换为指定的值,如果原始key不存在,则新增。

24、 (defrecord Employee [name room])

定义数据类型Employee, 其中有两个字段,名称分别为name和room。

(def emp (Employee. "John Smith" 304))

实例化一个Employee对象。

 (:name emp) 

获取emp对象中的name字段值。

25、  (str 1 2 3) -> "123"

字符串连接。

26、 (defnk f [:b 10] (inc b)) 

和defn的区别在于可以为参数指定默认值,实际调用的时候如果不传参数,会使用默认值进行计算,否则采用传入的参数

(f) -> 11

(f :b 100) -> 101

27、  (a/b)

调用命名空间a下的函数b.

28、 (.. class-or-object (method1 args) (method2 args) (method3 args) )

串行连续调用多个函数,第一个函数的返回值作为第二个函数的第一个参数,以此类推。

29、  下划线(_)

经常在clojure代码的let语句块中看到下划线,例如:(let [a (expr_for_a) _ (println "log") b (expr_for_b)] (expr_body))
由于let中参数绑定均为k v 形式,在有些情况下,我们只在乎v表达式的执行,而不在乎返回值,此时k的位置需要用下划线"_"来占据,依次告知编译器,我们不在乎表达式的返回值。

30、 for

作用和doseq类似,区别是可以使用额外的条件表达式进行笛卡尔积的筛选,支持的算子有:let  :when :while,例如:

(for [x [0 1 2 3 4 5] :let [y (* x 3)] :when (even? y)] y)  => (0 6 12)

将y设置为x*3,并且过滤掉奇数。

(for [x (range 3) y (range 3) :when (not= x y)] [x y]) => ([0 1] [0 2] [1 0] [1 2] [2 0] [2 1])

(for [x (range 3) y (range 3) :while (not= x y)] [x y]) => ([1 0] [2 0] [2 1])

将list x和y进行笛卡尔乘积,可以看到筛选算子when和while的区别在于while在list x中的每个元素第一次遇到不符合条件的list y中的元素时,list y后面的元素便全部忽略,从list x中的下一个元素开始重新对list y进行笛卡尔乘积。

31、 数据结构

‘(a b c) 链表

[a b c] 数组

#{a b c} set

{:a 1, :b 2, :c 3} map

32、  (System/currentTimeMillis)

斜杠用于表示静态方法调用

33、 (Integer. "100")

创建一个Integer对象,后面的参数是构造函数中所需参数。(注意Integer后面的点)

34、 (-> 100 (Integer.) .toString)

向右的单箭头称为thread-first,按照从左到右的顺序依次将第一个form的计算结果作为第一个参数传入紧接下来右边的form. 将各个处理节点作为数据处理管道串联起来。

35、 在定义宏的时候可以看到三个特殊的语法糖  ~  ~@  #

例如:

(defmacro mymacro [number & body]
    `(let [number# ~number] 
(cond 
(> number# 0) "positive"
(= number# 0) "zero"
:else ~@body)))

`称为syntax quote,表示宏主体里面的内容都会按照字面被展开,除了带波浪线的元素外,波浪线标注的元素number在展开时以其对应的值来代替,~@表示body是一个序列。number#是用来产生一个独特的符号名而不会和其他符号名冲突。
36、 获取map中指定key的值
(def simple_map {:a 1, :b 2, :c 3})
(:a simple_map)
37、 type hint
(defn ^String substr [^String s ^Integer begin ^Integer end] (.substring s begin end))
使用^提示clojure编译器,方法的参数和返回值的类型。
38、 #(get % key)

定义一个匿名函数,%表示函数的第一个参数(第2, 3个函数用%2, %3表示),该匿名函数获取参数中键值为key对应的value。

39、  ((comp str + )  1 2 3)

comp将多个函数按照right-to-left的顺序应用于指定数据集上,上述REPL运行结果为"6"。

40、 (concat [1] [2] '(3 4) [5 6 7] #{9 10 8})

连接集合 (1 2 3 4 5 6 7 8 9 10)

41、  (repeat 5 "x")

("x" "x" "x" "x" "x")

42、 (iterate inc 5)

迭代计算 (5 6 7 8 9 10 11 12 13 14 15 ... n

如果不用take配合,最终会导致OOM。

43、 (merge {:a 1 :b 2 :c 3} {:b 9 :d 4})

合并多个map,对于重复重现的Key,后面出现的会覆盖前面同样的Key。

44、  (set '(1 1 2 3 2 4 5 5))

返回一个唯一集合 #{1 2 3 4 5}

45、 (group-by f coll)

group-by根据算子f对集合coll进行排序,返回一个map,其中key为f计算的结果,key对应的value为coll中的对应元素,map按照key进行排序,

(group-by count ["a" "as" "asd" "aa" "asdf" "qwer"])  ->  {1 ["a"], 2 ["as" "aa"], 3 ["asd"], 4 ["asdf" "qwer"]}

46、 (vals {:a "foo", :b "bar"})

返回map对应value的序列 ("foo" "bar")


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值