Clojure语法学习-循环

do和块语句

在Scala中,花括号{}括起来的语句构成一个block,它的值就是最后一个语句的值。java

scala> val a = {
     | println("a")
     | 1}
a
a: Int = 1

{println("a"); 1}的值为1。ruby

在Clojure中,有时须要使多个form组成一个block, 这个block的值是最后一个form的值。这时候就用do函数

user=> (def a (do (println "a") 1))
a
#'user/a
user=> a
1

do takes any number of forms, evaluates them all, and returns the last.oop

do接受任意多的form做为参数,对它们分别求值,而后返回最后一个form的值。lua

 循环

有哪些要素才能构成一个循环?spa

在Java中scala

  1. 首先,咱们须要提供一个在每次循环中都会被执行的语句——循环体
  2. 若是不是无限循环,咱们须要提供退出条件,当这个条件知足时,再也不循环。

在Clojure中orm

  1. 首先,咱们须要提供一个在每次循环中都会被执行的语句——循环体
  2. 咱们须要提供循环条件。它这个条件知足时,继续下一次循环。

也就是说Java须要咱们告诉它何时退出循环,而Clojure须要咱们告诉它什么时候继续循环。blog

Java的for循环是这样的递归

for(int i = 0; i < 10; i++)
    System.out.println(i);

能够认为 i< 10, i++以及System.out.println(i)构成了循环体。退出条件为i<10。

while循环与for循环的不一样之处在于while没法声明只在循环内部使用的变量。在上边的for循环中, i只在循环内部使用。若是咱们想让while有相似的功能(固然,while没这功能),那么while须要接受一个初始化语法,变成

while(int i = 0)(i < 10){
    println(i);
    i++;
}

 在Clojure中,一样能够以binding的形式提供初始化语句, 以及提供循环体。这经过loop这种form来实现

(loop [bindings *] exprs*)

这就相似前边这个增强版的while。同时,在while循环中须要break来打破循环; 在Clojure中,咱们须要一种form来继续循环,这就是recur。能够认为Java的循环是主动的,而Clojure中的是被动的,你必须在代码中驱动它前进。

(loop [a 0] (if (< a 10) (do (println a) (recur (+ 1 a)))))

  recur使得程序从新开始执行loop。可是如何程序中是简单地从新执行loop,它就只是原地踏步,由于全部的绑定都始终是初始值。因此recur不只转变了程序的执行流,并且修改了loop开始的绑定。即,recur使得loop开始对a的绑定变成了(+ 1 a)。

假如,咱们在loop开始的时候多提供一个绑定

(loop [a 0 b 1] (if (< a 10) (do (println a) (recur (+ 1 a)))))

  REPL就会告诉咱们提供给recur的参数个数不对

CompilerException java.lang.IllegalArgumentException: Mismatched argument count to recur, expected: 2 args, got: 1

实际上,recur不只能够用于loop,也能够用于函数,它使得函数被从新执行。

举个书上的例子

(defn countdown [result x] (if (zero? x)
result
(recur (conj result x) (dec x))))

执行(count down [] 5)会输出返回值[5 4 3 2 1]

这种代码怎么看着这么眼熟呢?这不就像是尾递归吗?

相关文章
相关标签/搜索