do和块语句

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

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

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

在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.

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

循环

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

在Java中

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

在Clojure中

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

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

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]

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

Clojure语法学习-循环的更多相关文章

  1. doy05循环语法学习笔记

    doy05循环语法学习笔记 一.while循环语法: 1.基本用法示例 x = 1 while x <= 5: print(x) x += 1 2.死循环:永远不结束的循环 如:while Tr ...

  2. Golang 语法学习笔记

    Golang 语法学习笔记 包.变量和函数. 包 每个 Go 程序都是由包组成的. 程序运行的入口是包 main. 包名与导入路径的最后一个目录一致."math/rand" 包由 ...

  3. Swift高级语法学习总结(转)

    Swift高级语法学习总结 1.函数 1.1 func funcNmae()->(){} 这样就定义了一个函数,它的参数为空,返回值为空,如果有参数和返回值直接写在两个括号里就可以了 1.2 参 ...

  4. Swift基础语法学习总结(转)

    Swift基础语法学习总结 1.基础  1.1) swift还是使用// 和/* */ 来注释,并且/* */允许多行注释. 1.2) swift使用print和println打印,它的传参是一个泛型 ...

  5. Swift高级语法学习总结

    Swift基础语法学习总结Swift高级语法学习总结Swift语法总结补充(一) 1.函数 1.1 func funcNmae()->(){} 这样就定义了一个函数,它的参数为空,返回值为空,如 ...

  6. Swift基础语法学习总结

    Swift基础语法学习总结Swift高级语法学习总结Swift语法总结补充(一) 1.基础  1.1) swift还是使用// 和/* */ 来注释,并且/* */允许多行注释. 1.2) swift ...

  7. Robot Framework语法学习(一)

    Robot Framework语法学习: 一.变量的声明.赋值与使用 1.变量标识符:每个变量都可以用  变量标识符 ${变量名} 来表示. 2.变量声明:可以在TestSuite上点右键或者在Edi ...

  8. clisp, scheme 和 clojure 初学习

    clisp, scheme和clojure 初学习 1 clojure "clojure绝对会成为你的编程工具箱里的终极武器" "其他语言可能只是工具,但 Clojure ...

  9. 毕业设计 之 五 PHP语法学习笔记

    毕业设计 之 四 PHP语法学习笔记 作者:20135216 平台:windows10 软件:XAMPP,DreamWeaver 说明:该笔记是对网站编程语言的详细学习 一.PHP基础 0. 关于环境 ...

随机推荐

  1. Cocos2d-x中Vector<T>容器以及实例介绍

    Vector<T> 是Cocos2d-x 3.x推出的列表容器,因此它所能容纳的是Ref及子类所创建的对象指针,其中的T是模板,表示能够放入到容器中的类型,在Cocos2d-x 3.x中T ...

  2. iOS动画——文字晃动

    比如密码错误提示,需要文字左右晃动几次,以起到警示的作用. 为了调用使用方便,做一个分类.代码如下: .h文件 #import <QuartzCore/QuartzCore.h> @int ...

  3. Smarty控制foreach输出数量

    最近在搞ecshop,ecshop用的是smarty.在首页中想要修改展示的商品数量,但是用的是foreach,让我无从下手,在网上找了好久终于找到解决方案. <!--{foreach name ...

  4. 打包并发布自己的Android应用(eclipse)

    第一步,在Eclipse中选择需要打包的项目,然后右键--选择Export,会弹出一个打包的提示框,如下图所示. 按Next之后,会继续出现一个提示框,这里你可以选择自己需要打包的项目(默认是刚才选中 ...

  5. Tomcat上配置连接池{ connect error=Name [jdbc/OracleDB] is not bound in this Context. Unable to find [jdbc]}

    . 在学习期间,从未实践过在tomcat上配置连接池,今天终于实现一次,在tomcat玩了一把,不知道你是否现在有和我一样的困境.废话少说直接上代码   java  public static Con ...

  6. COM原理

    1, 进程内组件:服务程序杯加载到客户的进程空间,通常是DLL的形式.本地组件:服务程序与与客户程序在同一台电脑上,通常是EXE.远程组件: 服务程序与与客户程序在不同的电脑上,可以是DLL模块也可是 ...

  7. xamarin.ios 豆瓣电台视频教程

    视频中提到的网址: http://www.sufeinet.com/thread-655-1-1.html https://github.com/akfish/fm-terminal/blob/dev ...

  8. L012-oldboy-mysql-dba-lesson12

    L012-oldboy-mysql-dba-lesson12 graphite监控mysql可以达到秒级别 Zabbix for mysql NagiosXI daemontools linux    ...

  9. 利用Linux下的pthread_mutex_t类型来实现哲学家进餐问题

    首先说一下什么是哲学家进餐问题,这是操作系统课程中一个经典的同步问题, 问题如下:如上图,有6个哲学家和6根筷子(那个蓝色部分表示哲学家,那个紫色长条部分表示筷子),他们分别被编了0~5的号!如果某个 ...

  10. vs2013编译qt程序后中文出现乱码

    我的vs是2013版的,qt是5.4.2,在使用vc将程序编译好后并运行时在界面上输出的中文出现了乱码,在网上找了很长时间终于找到了解决方法: QString str = QStringLiteral ...