一、创建函数: 
fn: fn是一个宏,用于定义一个简单的函数,如下: 
[python] view plaincopy print?
  1. user=> (fn [] "hello")
  2. #<user$eval375$fn__376 user$eval375$fn__376@eabd2f>
  3. user=> ((fn [] "hello"))
  4. "hello"
  5. user=> ((fn [x] x) "hello") ; 带参数
  6. "hello"
  7. user=> ((fn [x] (str "hello " x)) "ithomer")
  8. "hello ithomer"

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

[python] view plaincopy print?
  1. user=> (#(/ % 3) 4)   ;结果为 4/3
  2. 4/3
  3. user=> (#(/ %2 %1) 3 4)   ;结果为 4/3
  4. 4/3
  5. user=> (#(apply / %&) 3 5 7)   ;结果为3/5/7
  6. 3/35

下面是几个定义函数的例子:

[python] view plaincopy print?
  1. user=> ((fn [x] (+ 1 x)) 3)  ;一个参数完成加1的功能
  2. 4
  3. user=> (#(+ 1 %) 3)  ;使用#符号完成加1的功能
  4. 4
  5. user=> ((fn [x y] (* x y)) 3 4)  ;两个参数,实现乘积的功能
  6. 12
  7. user=> (#(* %1 %2) 3 4)  ;使用#符号完成两个参数乘积的功能
  8. 12

defn: defn 宏用来定义一个函数。它的参数包括一个函数名字,一个可选的注释字符串,参数列表,然后一个方法体。而函数的返回值则是方法体里面最后一个表达式的值。所有的函数都会返回一个值, 只是有的返回的值是nil。

[python] view plaincopy print?
  1. user=> (defn f1 [] "hello ithomer")              ;定义无参函数
  2. #'user/f1
  3. user=> (f1)
  4. "hello ithomer"
  5. user=> (defn f2 [x] (format "hello %s" x))       ;定义一个参数函数
  6. #'user/f2
  7. user=> (f2 "ithomer")
  8. "hello ithomer"
  9. user=> (defn f3 [x y] (+ x y))                   ;定义两个参数相加的函数
  10. #'user/f3
  11. user=> (f3 2 4)
  12. 6
  13. user=> (defn f4 "f4 function comment" [] (println "f4 function here"))       ;带注释的函数
  14. #'user/f4
  15. user=> (f4)
  16. f4 function here
  17. nil
  18. user=> (doc f4)          ;通过doc查看函数注释信息
  19. -------------------------
  20. user/f4
  21. ([])
  22. f4 function comment
  23. nil
  24. user=> (defn f5 ([] (str "no parameter"))
  25. ([name] (str "my name is " name)))      ;定义重载的函数(无参数、一个参数)
  26. #'user/f5
  27. user=> (f5)                  ; 无参数
  28. "no parameter"
  29. user=> (f5 "clojure")        ; 一个参数
  30. "my name is clojure"
  31. user=> (defn f1 [& a] (str a))       ;定义变参函数
  32. #'user/f1
  33. user=> (f1 1 2 3)
  34. "(1 2 3)"
  35. user=> (defn m [& arg] (str arg ", size=" (count arg)))      ;定义变参函数
  36. #'user/m
  37. user=> (m 1 2 3 4 5)
  38. "(1 2 3 4 5), size=5"
  39. user=> (m "a" 1 2.3 -1)
  40. "(\"a\" 1 2.3 -1), size=4"
  41. user=> (defn exp [a f1 b f2 c] (f2 (f1 a b) c))              ;函数作为参数
  42. #'user/exp
  43. user=> (exp 5 - 2 + 3)
  44. 6
  45. user=> (defn f [a] (fn [b] (- a b)))                     ;函数作为返回值
  46. #'user/f
  47. user=> ((f 7) 4)
  48. 3
defn-: defn-与defn功能一致,都是用于定义函数的,defn-定义的函数作用域是私有的,而defn定义的函数是公有的,如下: 
[python] view plaincopy print?
  1. user=> (ns test1)                    ;ns的意思是切换到指定的命名空间,如果不存在,则新建该命名空间
  2. nil
  3. test1=> (defn- foo [] "hello ithomer")           ;定义私有函数foo,返回字符串world
  4. #'test1/foo
  5. test1=> (defn bar [] (str "hello " (foo)))       ;定义公有函数bar,并调用私有函数foo
  6. #'test1/bar
  7. test1=> (foo)            ;当前命名空间内调用foo函数
  8. "hello ithomer"
  9. test1=> (bar)            ;当前命名空间内调用bar函数
  10. "hello hello ithomer"
  11. test1=> (ns test2)       ;切换到test2命名空间中
  12. nil
  13. test2=> (test1/bar)      ;调用test1命名空间的bar函数,返回成功
  14. "hello hello ithomer"
  15. test2=> (test1/foo)      ;调用test1命名空间的foo函数,出现异常,提示test1的foo函数不是公开的
  16. java.lang.IllegalStateException: var: #'test1/foo is not public (NO_SOURCE_FILE:79)
组合函数comp: 形如   ((comp f1 f2 .. fn) arg1 arg2 .. argn)  
就是对参数从右到左组合执行所有函数,可以转变为: (f1 (f2 (.. (fn arg1 arg2 .. argn))))
举例如下: 
[python] view plaincopy print?
  1. user=> (defn f [x y] (- (* x y)));使用defn定义函数方式
  2. #user/f
  3. user=> (f 2 4)
  4. -8
  5. user=> (def fc (comp - *));使用comp定义组合函数方式
  6. #user/fc
  7. user=> (fc 2 4)
  8. -8

偏函数partial: 形如 ((partial  f  arg1 arg2 .. argn)  arga argb .. argz)

就是执行: (f  arg1 arg2 .. argn  arga argb .. argz) 
注意:偏函数的第一个参数是一个函数,后面至少有1个其他参数 
partial函数称为“偏函数”或者“部分完整函数”,因为它是不完整的,定义也用def而不是defn。 
[python] view plaincopy print?
  1. user=> (defn f [n] (* n 10));正常函数
  2. #'user/f
  3. user=> (f 2)
  4. 20
  5. user=> (def fp (partial * 10));偏函数
  6. #'user/fp
  7. user=> (fp 2)
  8. 20

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

[python] view plaincopy print?
  1. user=> (def consf (constantly "a"))
  2. #'user/consf
  3. user=> (consf 1 2 3)
  4. "a"
  5. user=> (consf "a")
  6. "a"
  7. user=> (consf [1 2 3])
  8. "a"

二、函数调用 
->:宏-> 我们也称为 “thread” 宏,它本质上是调用一系列的函数,前一个函数的返回值作为后一个函数的参数,返回最后一次函数调用的值,比如下面两行代码的作用是一样的:

[python] view plaincopy print?
  1. user=> (.toUpperCase "a b c d")
  2. "A B C D"
  3. user=> (.replace (.toUpperCase "a b c d") "A" "X")
  4. "X B C D"
  5. user=> (.split (.replace (.toUpperCase "a b c d") "A" "X") " ")              ; 数组
  6. #<String[] [Ljava.lang.String;@41ab11b0>
  7. user=> (first (.split (.replace (.toUpperCase "a b c d") "A" "X") " "))
  8. "X"
  9. user=> (-> "a b c d" .toUpperCase)
  10. "A B C D"
  11. user=> (-> "a b c d" .toUpperCase (.replace "A" "X"))
  12. "X B C D"
  13. user=> (-> "a b c d" .toUpperCase (.replace "A" "X") (.split " "))            ; 数组
  14. #<String[] [Ljava.lang.String;@58e41bc3>
  15. user=> (-> "a b c d" .toUpperCase (.replace "A" "X") (.split " ") first)
  16. "X"
这样调用的好处是更少的(),也更接近于scala的习惯。 
[python] view plaincopy print?
  1. user=> (-> (/ 144 12) (/ 2 3) str keyword list)
  2. (:2)
  3. user=> (list (keyword (str (/ (/ 144 12) 2 3))))
  4. (:2)
  5. user=> (-> (/ 144 12))
  6. 12
  7. user=> (-> (/ 144 12) (/ 2 3))
  8. 2
  9. user=> (-> (/ 144 12) (/ 2 3) str)
  10. "2"
  11. user=> (-> (/ 144 12) (/ 2 3) str keyword)
  12. :2
  13. user=> (-> (/ 144 12) (/ 2 3) str keyword list)
  14. (:2)
  15. user=> (/ (/ 144 12) 2 3)
  16. 2
  17. user=> (str (/ (/ 144 12) 2 3))
  18. "2"
  19. user=> (keyword (str (/ (/ 144 12) 2 3)))
  20. :2
  21. user=> (list (keyword (str (/ (/ 144 12) 2 3))))
  22. (:2)
上面两句结果一样。 
->>: 后面的函数迭代使用之前的函数结果作为最后一个参数,返回最后一次函数调用的值,试看下面两个语句: 
[python] view plaincopy print?
  1. user=> (-> 10 (/ 3))      ; 10/3  10作为/函数第一个参数
  2. 10/3
  3. user=> (->> 10 (/ 3))  ; 3/10  10作为/函数最后一个参数
  4. 3/10
eval: eval解析表达式数据结构(不是字符串),并返回结果。 
[python] view plaincopy print?
  1. user=> (eval (str "(println 1)"))            ;str函数返回字符串
  2. "(println 1)"
  3. user=> (read-string "(println 1)")           ;而read-string函数用于从字符串中读取对象
  4. (println 1)
  5. user=> (eval (read-string "(println 1)"))
  6. 1
  7. nil

apply函数: apply 把给定的集合里面的所有元素一次性地给指定的函数作为参数调用,然后返回这个函数的返回值。可以把apply看作是SQL里面的聚合函数,如下:

[python] view plaincopy print?
  1. user=> (apply + [1 2 3 4])
  2. 10

三、函数检查 
fn?: fn?用于检查给定的参数是否为函数,是返回true,否则返回false,如:

[python] view plaincopy print?
  1. user=> (fn? #("test"))
  2. true
  3. user=> (fn? 1)
  4. false
  5. user=> (fn? nil)
  6. false
  7. user=> (fn? +)
  8. true
  9. user=> (fn? mod)
  10. true
  11. user=> (fn? rem)
  12. true
  13. user=> (fn? =)
  14. true
  15. user=> (fn? with-precision)
  16. java.lang.Exception: Can't take value of a macro: #'clojure.core/with-precision (NO_SOURCE_FILE:32)
  17. user=> (fn? min)
  18. true
  19. user=> (fn? >=)
  20. true

参考推荐:

clojure 学习

Clojure 学习入门(6)- 函数定义相关推荐

  1. Clojure 学习入门(6)—— 函数定义

    一.创建函数: fn: fn是一个宏,用于定义一个简单的函数,如下:  user=> (fn [] "hello") #<user$eval375$fn__376 us ...

  2. 【python教程入门学习】Python函数定义及传参方式详解(4种)

    这篇文章主要介绍了Python函数定义及传参方式详解(4种),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧 一.函数初识 1.定 ...

  3. Clojure 学习入门(18)—— 数据类型

    如何表示和处理数据 Clojure是一种动态类型语言,这意味着你在程序中永远不需要明确定义符号.函数.或者参数的数据类型.但是,所有的值仍然有一个类型.字符串时是字符串,数字是数字,列表是列表,等等. ...

  4. Python学习笔记 - 探索函数定义和使用

    大家好,我是Mr数据杨,你们有没有读过<三国演义>呢?没错,将以这个经典的古代战争史诗为引,来探索Python的诸多神奇之处. 首先来说说函数的重要性.诸葛亮一生献出了不少锦囊妙计,这些计 ...

  5. Clojure 学习入门(13)- binding

    Clojure里面是不支持变量的.Binding跟变量有点像,但是在被赋值之前是不允许改的,包括:全局binding, 线程本地(thread local)binding, 以及函数内的本地bindi ...

  6. Clojure 学习入门(16)- 正则表达式

    一.创建正则表达式  re-pattern函数:  函数 (re-pattern) 接受一个字符串参数,返回一个正则表达式样式(java.util.regex.Pattern类的实例).这个样式能用于 ...

  7. Clojure 学习入门(15)- 条件判断

    一.标准的流程控制  if:  将一个判断表达式作为它的第一个参数进行求值.如果求值为true,那么就返回它的第二个参数(相当于"then"子句)的求值结果.如果结果为false( ...

  8. Clojure 学习入门(14)- 循环控制

    Clojure 基于函数的流程控制  repeatedly 字面意思为重复函数.一般的用法如下: user=> (repeatedly 5 #(rand-int 11)) (6 8 2 6 6) ...

  9. Clojure 学习入门(11)- 宏 macro

    clojure macro宏在运行之前机械展开,定义宏相当于给语言增加新特性,写宏的*原则*:  能写成函数就不要用宏(因为写宏没有写函数简单直观,容易写错,需要先在 REPL 中测试一番) 只有不得 ...

最新文章

  1. python 怎样让 print 打印的结果不换行
  2. MySQL 高频 100 问
  3. 并发编程:原子性问题,可见性问题,有序性问题。
  4. Java HashSet源码解析
  5. linux --- 基础指令
  6. 2019年度年中回顾总结_我的2019年回顾和我的2020年目标(包括数量和收入)
  7. 数据链路层(学习笔记)
  8. Java的位运算符具体解释实例——与(amp;)、非(~)、或(|)、异或(^)
  9. jvm 初始化之 cinit , init
  10. android return 如何跳出两个循环_PHP跳出循环的方法
  11. 【转】opencv 配置
  12. CleanMyMac X2021专业苹果电脑系统优化工具
  13. 基于51单片机智能车流量检测车量统计系统设计
  14. mybatis中selectOne方法分析
  15. der解码规则_[转] DER编码和ASN.1
  16. linux glog使用
  17. 聊一聊前端性能优化 CRP
  18. p73 应急响应-WEB 分析 phpjavaweb自动化工具
  19. h5 ios中软键盘弹起后 fixed定位失效
  20. 你是开发工程师、程序员还是码农?

热门文章

  1. C++的MFC 与 HTML 双向通讯
  2. (8). 使用JPA保存数据【从零开始学Spring Boot】
  3. Google 开源 VHP 震动触觉平台,降低触觉设备开发难度
  4. Android开发者网址导航
  5. 介绍几种不同的标志符号 CMC CPA CPE CMA
  6. 【超参数寻优】粒子群算法(PSO) 超参数寻优的python实现
  7. Focal loss原理解析
  8. 机器学习--支持向量机实战(二)简易SMO算法实现
  9. final修饰的类有什么特点?
  10. python转义引号的作用_在Jinja2中渲染时转义双引号