Clojure是一门Lisp方言——确切地说,是一门JVM上的Lisp方言——也是一门非纯粹的函数式语言。

Clojure理所当然地秉承了Lisp“代码即数据( code is data! )”的设计哲学, 代码和值一样处于同等地位。

这一著名特性,内含了无穷无尽魔法威力,并通过括号体现出强大的语言表现能力。

但是也正是因为这个,该特性正是让无数熟谙其它语言模式的开发者难以跨越的一道门槛。

本文希望通过解读来帮助大家更好的理解和使用这个特性。

一、表达式

首先我们来说下表达式的概念 。

在clojure中,代码就是由表达式组成的,每个表示每个表达式都会产生一个值。

常见的表达式如:

60

[2  4  6]

(+ 1 2)

(average [2 3 4])

1)上面的第一个表达式就是一个字面常量,这里是一个整数。

2)第二个是个整数序列。

3)第3和4 都是函数调用,Clojure中,小括号 () 表示函数调用,括号中的第一个值是函数名,剩下的值是参数,整个调用表达式被求值的结果作为调用的返回值。

在Clojure中,类似其它语言的运算符,都可以看做是函数,这也为何上面例子中的 (+ 1 2) 这个表达式中 + 号放在前面的原因。

二、函数

函数定义本身也是一个表达式,调用宏defn定义,也是放到 () 中,其函数体也是由1个或多个表达式组成。

语法: (defn 函数名 [参数列表] 表达式1  表达式2 .... 表达式n)

上面定义返回的是一个函数。

函数调用

语法: (函数名 表达式1  表达式2 .... 表达式n)

上面的表达式就是传递给函数的参数值。

在Clojure中,函数既可以直接被调用,用()调用。 也可以作为参数传递给函数,也可以作为函数执行的返回值。

例1:

user=> (defn hello[] 10)
#'user/hello
user=> (hello)
10

例2:

user=> (defn hello[a b] (+ a b))
#'user/hello
user=> (hello 3 4)
7

例3:

user=> (defn hello[a b] (+ a b) (* a b) )
#'user/hello
user=> (hello 2 4)
8

例4:

user=> (defn hello[a b] (* (+ a b) (- a b)) )
#'user/hello
user=> (hello 5 3)
16

三、匿名函数

Clojure中,强调“代码即数据”,这也意味者代码(即函数)可以像数据一样随意的被传递、返回等。

如果每次都需要显示的去定义一个函数,特别是对一些一次性操作,会很麻烦,也会增加代码的复杂性,不简介,还可能会导致命名冲突与覆盖,留下隐患。

很多场景下,其实只需要函数体和参数,对函数的名称不关心。这时就可以通过匿名函数来实现。

定义匿名函数的语法是:#(表达式)

传入的参数用 % 占位符来标记。

其中%表示唯一的参数;%1、%2 ..依次表示第1、2、..个参数;%&表示所有参数

例1:

user=> (defn hello[para value] (para value))
#'user/hello
user=> (hello #(print %) 10)
10nil

上面第一句代码中para参数是一个函数,第二句 #(print %) 定义了一个匿名函数并传给hello方法。

例:2

user=>  (defn hello[para value1 value2] (para value1 value2))
#'user/hello
user=> (hello #(* %1 %2) 2 3)
6

user=> (hello #(println %&) 2 3)
(2 3)

例3:

user=> (#(+ %1 %2) 10 20)
30

上面的语句与如下语句效果一样

user=> ((defn fun[a b] (+ a b)) 10 20)
30

只不过上面这个语句定义的是个有名额函数,函数名为fun。

除了在定义时被使用外,后续还能继续通过名称被调用

user=> (fun 2 8)
10

总结一下,clojure代码就是由 很多的 () 函数调用(嵌套)完成。注意几个语法的区别:

() 这个是函数调用,第一个值是函数名,后续值是参数。 返回的是函数执行的结果。

'() 是 列表,括号中是空格分隔的表达式。返回的是列表对象。

#() 是匿名函数,返回的是一个函数。注意是函数,不是函数调用。

Clojure学习:表达式与函数的更多相关文章

  1. JS学习笔记3_函数表达式

    1.函数表达式与函数声明的区别 函数声明有“提升”(hoisting)的特性,而函数表达式没有.也就是说,函数声明会在加载代码时被预先加载到context中,而函数表达式只有在执行表达式语句时才会被加 ...

  2. iOS学习05C语言函数

    本次主要是学习和理解函数,函数树状图如下: 1.函数的声明和定义 函数定义的四要素分别为: 返回值类型 :函数的结果值类型,函数不能返回数组. 指定返回类型是void类型说明函数没有返回值. 函数名 ...

  3. Clojure学习02:语法

    相比我们传统的 c ,java ,python ,javascript等,Clojure的语法比较特别,初一看,还可能会有些不适应. 本文来介绍下Clojure的语法特点. 一.表达式 所有的Cloj ...

  4. Clojure学习03:数据结构(集合)

    Clojure提供了几种强大的数据结构(集合) 一.集合种类 1.vector 相当于数组,如: [2  3   5]  ,  ["ad"  "adas"  & ...

  5. Haskell学习-高阶函数

    原文地址:Haskell学习-高阶函数 高阶函数(higher-order function)就是指可以操作函数的函数,即函数可以作为参数,也可以作为返回结果.有了这两个特性,haskell可以实现许 ...

  6. PostgreSQL学习手册(五) 函数和操作符

    PostgreSQL学习手册(五) 函数和操作符 一.逻辑操作符:    常用的逻辑操作符有:AND.OR和NOT.其语义与其它编程语言中的逻辑操作符完全相同. 二.比较操作符:    下面是Post ...

  7. js函数表达式和函数声明的区别

    我们已经知道,在任意代码片段外部添加包装函数,可以将内部的变量和函数定义"隐 藏"起来,外部作用域无法访问包装函数内部的任何内容. 例如: var a = 2; function ...

  8. python学习笔记(4)--函数

    1.函数 函数是指将一组语句的集合通过一个名字封装起来.要想执行这个函数,只需调用其函数名即可. 函数的特性: 1.减少重复代码 2.使程序变的课扩展 3.使程序变得易维护 语法定义: def pri ...

  9. 学习js回调函数

    <!DOCTYPE HTML> <html> <head> <meta charset="GBK" /> <title> ...

  10. js基础:函数表达式和函数声明

    函数表达式和函数声明的区别.实际上,解析器在向执行环境中加载数据是,对函数表达式和函数声明并非一视同仁.解析器会率先读取函数声明,并使其在执行任何代码之前可用.而函数表达式,则必须等到解析器执行到它所 ...

随机推荐

  1. 读书笔记: 深入浅出node.js

    >> 深入浅出node.js node.js是c++编写的js运行环境 浏览器: 渲染引擎 + js引擎 后端的js运行环境 node.js用google v8引擎,同时提供很多系统级的A ...

  2. C#中WebClient使用DownloadString中文乱码的解决办法

    原文:C#中WebClient中文乱码的解决办法 第一次尝试: string question = textBox1.Text.ToString(); WebClient client= new We ...

  3. CTreeCtrl 控件使用总结

    一 基础操作  1 插入节点 1)插入根节点 [cpp] view plaincopy //插入根节点 HTREEITEM hRoot; CString str=L"ROOT" h ...

  4. Js用正则表达式验证字符串

    js 常用正则表达式表单验证代码 作者: 字体:[增加 减小] 类型:转载 js 常用正则表达式表单验证代码,以后大家就可以直接使用了. 正则表达式使用详解 简介 简单的说,正则表达式是一种可以用于模 ...

  5. 在SQL 中生成JSON数据

    这段时间接手一个数据操作记录的功能,刚拿到手上的时候打算用EF做,后来经过仔细考虑最后还是觉定放弃,最后思考再三决定: 1.以模块为单位分表.列固定(其实可以所有的操作记录都放到同一个表,但是考虑到数 ...

  6. iOS开发之第三方登录微博-- 史上最全最新第三方登录微博方式实现

    相关资源地址: 本项目demo地址 :  https://github.com/zhonggaorong/weiboSDKDemo 最新SDK下载:  最新微博SDK 官网注册地址:点击打开链接 最新 ...

  7. new[] class deconstructor

    Class class(); Class *class1=new class; class1=&class; delete class1;   // Assert 指针指向的是一个栈中的对象, ...

  8. python成长之路——第八天

    pickle,load :切记:如果load的是个对象的话,必须导入构建这个对象的类     封装 类和对象的关系: 每个对象里都有一个类对象指针,指向类     继承:支持单继承和多继承 print ...

  9. 转:JS线程和JS阻塞页面加载的问题

    前几日写了一篇文章,介绍了js阻塞页面加载的问题.当时是通过例子来验证的.今天,我介绍一下浏览器内核,从原理上介绍一下js阻塞页面加载的原因. 浏览器的内核是多线程的,它们在内核制控下相互配合以保持同 ...

  10. Windows Phone 8初学者开发—第10部分:数据绑定应用程序和透视应用程序项目模板简介

    原文 Windows Phone 8初学者开发—第10部分:数据绑定应用程序和透视应用程序项目模板简介 原文地址: http://channel9.msdn.com/Series/Windows-Ph ...