理解clojure语法(2)

注:本文长期更新
本文梳理一些clojure的常用知识点,惯用法?maybe
1.#'表示取得变量对象本身,

var-quote (#')
#'x ⇒ (var x)

这是#的一个reader宏,作用是:

get Var object instead of the value of a symbol (var-quote),

. The reader macro #’x expands to (var x)

boot.user=> (def x 1)
#'boot.user/x
boot.user=> #'x
#'boot.user/x
boot.user=> x
1

深层次的了解可以看第21点。

2.Loop和recur常一起用于循环

boot.user=> (loop [i 0]
       #_=> (when (< i 5)
       #_=> (println i)
       #_=> (recur (inc i))))
0
1
2
3
4
nil

3.doseq一般和range常放在一起使用

boot.user=> (doseq [n (range 3)]
       #_=> (println n))
0
1
2
nil

range一个参数表示从0开始到这个数为止。

boot.user=> (doseq [n (range 1 3)]
       #_=> (println n))
1
2
nil

range可以有两个参数或者一个参数,三个参数也可以(第三个参数表示step步子的大小),

boot.user=> (doseq [n (range 1 8 3)]
       #_=> (println n))
1
4
7
nil

4.for用于枚举的循环,抑或全排列组合

boot.user=> (for [x [0 1] y [1 3]]
       #_=> [x y])
([0 1] [0 3] [1 1] [1 3])

https://clojuredocs.org/clojure.core/for这里有很多for更高级的例子

5.while

boot.user=> (def a (atom 5))
#'boot.user/a
boot.user=> (while (pos? @a) (do (println @a) (swap! a dec)))
5
4
3
2
1
nil

6.函数式编程中的尾递归

“尾调用优化”对递归操作意义重大,所以一些函数式编程语言将其写入了语言规格。ES6也是如此,第一次明确规定,所有 ECMAScript 的实现,都必须部署”尾调用优化”。这就是说,在 ES6 中,只要使用尾递归,就不会发生栈溢出,相对节省内存—http://www.ruanyifeng.com/blog/2015/04/tail-call.html

对于阶乘操作:

(defn factorial ([x] (factorial 1 x))
      ([accum x]
        (if (= x 1) accum
                    (factorial (*' accum x) (- x 1))
                    )))
(factorial 1000)

结果

这里使用 *'而不是*的原因是*'支持任意精度,而*在数据长度超过long的情况下会发生溢出。

*’
returns the product of nums. (*’) returns 1. Supports arbitrary precision.

因为递归调用(比如阶乘和斐波拉契数列)的函数容易引起内存溢出,这样使用尾递归可以极少的减少内存消耗,否则可能会引起栈溢出,尾调用由于是函数的最后一步操作,所以不需要保留外层函数的调用记录,因为调用位置、内部变量等信息都不会再用到了,只要直接用内层函数的调用记录,取代外层函数的调用记录就可以了。

7.some 断言
判断某一个集合是否有满足pred的值,如果有返回true 否则false

user=> (some nil? [1 2 ""])
nil
user=> (some nil? [1 2 "" nil])
true

8.调用java类的方法 . 和..
一般步骤有:
导入
创建对象
调用方法.

.
special form
Usage: (.instanceMember instance args*)
(.instanceMember Classname args*)
(Classname/staticMethod args*)
Classname/staticField
The instance member form works for both fields and methods.
They all expand into calls to the dot operator at macroexpansion time.
Please see http://clojure.org/java_interop#dot

连续调用方法.. 前一个函数的返回值,作为后一个函数的第一个参数

..
macro
Usage: (.. x form)
(.. x form & more)
form => fieldName-symbol or (instanceMethodName-symbol args*)
Expands into a member access (.) of the first member on the first
argument, followed by the next member on the result, etc. For
instance:
(.. System (getProperties) (get “os.name”))
expands to:
(. (. System (getProperties)) (get “os.name”))
but is easier to write, read, and understand.

使用java有几个互操作的工具:doto class instance?

doto macro

Usage: (doto x & forms) Evaluates x then calls all of the methods and functions with the value of x supplied at the front of the given arguments. The forms are evaluated in order. Returns x.

user=> (doto (new java.util.HashMap) (.put "a" 1) (.put "b" 2))
{
  "a" 1, "b" 2}
;doto就是对实体进行一系列操作的一个form

user=> (def a (String. "abc"))
#'user/a
user=> (class a)
java.lang.String
user=> (instance? String a)
true
user=> (.charAt  a 0)
/a
user=> (.. a (charAt 0) toString)
"a"

9.some->->的用法更有包容性

(some-> expr & forms)
When expr is not nil, threads it into the first form (via ->),
and when that result is not nil, through the next etc

user=> (some-> {:a 1} :b inc)
nil
user=> (-> {:a 1} :b inc)
NullPointerException   clojure.lang.Numbers.ops (Numbers.java:1013)

因为(inc nil)的操作是会报错的,some->在某个结果为nil的时候就会返回nil,而不再进行后续的操作了,因而不会报错。

10.partition简单给集合分区

(partition n coll)(partition n step coll)(partition n step pad coll)
Returns a lazy sequence of lists of n items each, at offsets step
apart. If step is not supplied, defaults to n, i.e. the partitions
do not overlap. If a pad collection is supplied, use its elements as
necessary to complete last partition upto n items. In case there are
not enough padding elements, return a partition with less than n items.

partiton-by和group-by按照特定的条件给集合分区。

boot.user=> (partition-by #(= 3 %) [1 2 3 4 5])
((1 2) (3) (4 5))
boot.user=> (partition-by #(= 3 %) [1 2  4 5])
((1 2 4 5))
boot.user=> (partition-by #(= 3 %) [1 2  4 5 3])
((1 2 4 5) (3))
boot.user=> (partition-by odd? [1 1 1 2 2 3 3])
((1 1 1) (2 2) (3 3))
boot.user=> (partition-by odd? [1 1 1 2 3 3])
((1 1 1) (2) (3 3))
boot.user=> (partition-by odd? [1 1 1  3 3])
((1 1 1 3 3))
boot.user=> (partition-by even? [1 1 1 2 2 3 3])
((1 1 1) (2 2) (3 3))
boot.user=> (partition-by even? [1 1 1 3 3])
((1 1 1 3 3))
boot.user=> (partition-by even? [1 1 1 3 3 2])

group-by的结果还有点不一样,group-by返回的是一个key list的map。

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

发散:mysql的partition 大数据情况下的分区:把数据库的表分成几个小部分;好处:可以提高数据库的性能;http://blog.51yip.com/mysql/1013.html

11.associative?

Usage: (associative? coll)
Returns true if coll implements Associative

clojure数据结构的map vector都是associative结构的,但是list,set结构不是。
associative结构的数据和非associative结构的有哪些差别呢?
首先看看vector和list的差别?

vector和数组类似,它拥有一段连续的内存空间,并且起始地址不变,因此它能非常好的支持随机存取(即使用[]操作符访问其中的元素),但由于它的内存空间是连续的,所以在中间进行插入和删除会造成内存块的拷贝(复杂度是O(n)),另外,当该数组后的内存空间不够时,需要重新申请一块足够大的内存并进行内存的拷贝。这些都大大影响了vector的效率。
list是由数据结构中的双向链表实现的,因此它的内存空间可以是不连续的。因此只能通过指针来进行数据的访问,这个特点使得它的随机存取变的非常没有效率,需要遍历中间的元素,搜索复杂度O(n),因此它没有提供[]操作符的重载。但由于链表的特点,它可以以很好的效率支持任意地方的删除和插入。

所以vector是关联数组,而list不是。

boot.user=> (associative? [])
true
boot.user=> (associative? ())
false
boot.user=> (associative? '())
false
boot.user=> (associative? #( 1 2))
false
boot.user=> (associative? {:a 1})
true

那么为什么要使用associative结构?associative结构支持哪些操作?

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Clojure编程是一本介绍Clojure编程语言的书籍,可以作为学习和参考的资源。这本书涵盖了Clojure语言的基础知识,包括语法、数据结构、函数式编程等内容。它适用于初学者和有一定编程背景的人士。 这本书主要分为四个部分。第一部分介绍了Clojure语言的基本语法和数据类型,例如列表、向量、集合等。它还介绍了命名空间和宏的概念,帮助读者理解Clojure的核心思想和设计。 第二部分深入探讨了函数式编程的概念和技巧。它讨论了函数的定义和使用,以及函数式编程的特点和好处。此外,它还介绍了Clojure中的高阶函数和持久化数据结构,以及如何处理并发编程和错误处理等主题。 第三部分介绍了Clojure编程的实践技巧和最佳实践。它包括代码组织、测试、调试和性能优化等方面的内容。它还提供了一些现实世界的示例和项目案例,帮助读者将Clojure应用到实际的开发中。 最后一部分讨论了Clojure与其他编程语言和工具的集成。它涵盖了与Java的互操作性、使用Clojure开发Web应用、使用Clojure与数据库交互等方面的内容。同时还介绍了Clojure生态系统中的一些重要库和框架,例如Ring和Compojure等。 总的来说,Clojure编程是一本全面而深入的Clojure学习资源,可以帮助读者掌握该语言的各个方面。无论是初学者还是有经验的开发人员,都可以从这本书中收获到对Clojure编程的深入理解和实践经验。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值