Clojure 学习入门(6)- 函数定义
- user=> (fn [] "hello")
- #<user$eval375$fn__376 user$eval375$fn__376@eabd2f>
- user=> ((fn [] "hello"))
- "hello"
- user=> ((fn [x] x) "hello") ; 带参数
- "hello"
- user=> ((fn [x] (str "hello " x)) "ithomer")
- "hello ithomer"
简短的函数可以使用#(),%表示唯一的参数;%1、%2 ..依次表示第1、2、..个参数;%&表示所有参数,如下:
- user=> (#(/ % 3) 4) ;结果为 4/3
- 4/3
- user=> (#(/ %2 %1) 3 4) ;结果为 4/3
- 4/3
- user=> (#(apply / %&) 3 5 7) ;结果为3/5/7
- 3/35
下面是几个定义函数的例子:
- user=> ((fn [x] (+ 1 x)) 3) ;一个参数完成加1的功能
- 4
- user=> (#(+ 1 %) 3) ;使用#符号完成加1的功能
- 4
- user=> ((fn [x y] (* x y)) 3 4) ;两个参数,实现乘积的功能
- 12
- user=> (#(* %1 %2) 3 4) ;使用#符号完成两个参数乘积的功能
- 12
defn: defn 宏用来定义一个函数。它的参数包括一个函数名字,一个可选的注释字符串,参数列表,然后一个方法体。而函数的返回值则是方法体里面最后一个表达式的值。所有的函数都会返回一个值, 只是有的返回的值是nil。
- user=> (defn f1 [] "hello ithomer") ;定义无参函数
- #'user/f1
- user=> (f1)
- "hello ithomer"
- user=> (defn f2 [x] (format "hello %s" x)) ;定义一个参数函数
- #'user/f2
- user=> (f2 "ithomer")
- "hello ithomer"
- user=> (defn f3 [x y] (+ x y)) ;定义两个参数相加的函数
- #'user/f3
- user=> (f3 2 4)
- 6
- user=> (defn f4 "f4 function comment" [] (println "f4 function here")) ;带注释的函数
- #'user/f4
- user=> (f4)
- f4 function here
- nil
- user=> (doc f4) ;通过doc查看函数注释信息
- -------------------------
- user/f4
- ([])
- f4 function comment
- nil
- user=> (defn f5 ([] (str "no parameter"))
- ([name] (str "my name is " name))) ;定义重载的函数(无参数、一个参数)
- #'user/f5
- user=> (f5) ; 无参数
- "no parameter"
- user=> (f5 "clojure") ; 一个参数
- "my name is clojure"
- user=> (defn f1 [& a] (str a)) ;定义变参函数
- #'user/f1
- user=> (f1 1 2 3)
- "(1 2 3)"
- user=> (defn m [& arg] (str arg ", size=" (count arg))) ;定义变参函数
- #'user/m
- user=> (m 1 2 3 4 5)
- "(1 2 3 4 5), size=5"
- user=> (m "a" 1 2.3 -1)
- "(\"a\" 1 2.3 -1), size=4"
- user=> (defn exp [a f1 b f2 c] (f2 (f1 a b) c)) ;函数作为参数
- #'user/exp
- user=> (exp 5 - 2 + 3)
- 6
- user=> (defn f [a] (fn [b] (- a b))) ;函数作为返回值
- #'user/f
- user=> ((f 7) 4)
- 3
- user=> (ns test1) ;ns的意思是切换到指定的命名空间,如果不存在,则新建该命名空间
- nil
- test1=> (defn- foo [] "hello ithomer") ;定义私有函数foo,返回字符串world
- #'test1/foo
- test1=> (defn bar [] (str "hello " (foo))) ;定义公有函数bar,并调用私有函数foo
- #'test1/bar
- test1=> (foo) ;当前命名空间内调用foo函数
- "hello ithomer"
- test1=> (bar) ;当前命名空间内调用bar函数
- "hello hello ithomer"
- test1=> (ns test2) ;切换到test2命名空间中
- nil
- test2=> (test1/bar) ;调用test1命名空间的bar函数,返回成功
- "hello hello ithomer"
- test2=> (test1/foo) ;调用test1命名空间的foo函数,出现异常,提示test1的foo函数不是公开的
- java.lang.IllegalStateException: var: #'test1/foo is not public (NO_SOURCE_FILE:79)
- user=> (defn f [x y] (- (* x y)));使用defn定义函数方式
- #user/f
- user=> (f 2 4)
- -8
- user=> (def fc (comp - *));使用comp定义组合函数方式
- #user/fc
- user=> (fc 2 4)
- -8
偏函数partial: 形如 ((partial f arg1 arg2 .. argn) arga argb .. argz)
注意:偏函数的第一个参数是一个函数,后面至少有1个其他参数
partial函数称为“偏函数”或者“部分完整函数”,因为它是不完整的,定义也用def而不是defn。
- user=> (defn f [n] (* n 10));正常函数
- #'user/f
- user=> (f 2)
- 20
- user=> (def fp (partial * 10));偏函数
- #'user/fp
- user=> (fp 2)
- 20
constantly函数: constantly函数接受一个参数x,并返回一个变参函数,该变参函数无论参数是什么,都返回这个x值。
- user=> (def consf (constantly "a"))
- #'user/consf
- user=> (consf 1 2 3)
- "a"
- user=> (consf "a")
- "a"
- user=> (consf [1 2 3])
- "a"
二、函数调用
->:宏-> 我们也称为 “thread” 宏,它本质上是调用一系列的函数,前一个函数的返回值作为后一个函数的参数,返回最后一次函数调用的值,比如下面两行代码的作用是一样的:
- user=> (.toUpperCase "a b c d")
- "A B C D"
- user=> (.replace (.toUpperCase "a b c d") "A" "X")
- "X B C D"
- user=> (.split (.replace (.toUpperCase "a b c d") "A" "X") " ") ; 数组
- #<String[] [Ljava.lang.String;@41ab11b0>
- user=> (first (.split (.replace (.toUpperCase "a b c d") "A" "X") " "))
- "X"
- user=> (-> "a b c d" .toUpperCase)
- "A B C D"
- user=> (-> "a b c d" .toUpperCase (.replace "A" "X"))
- "X B C D"
- user=> (-> "a b c d" .toUpperCase (.replace "A" "X") (.split " ")) ; 数组
- #<String[] [Ljava.lang.String;@58e41bc3>
- user=> (-> "a b c d" .toUpperCase (.replace "A" "X") (.split " ") first)
- "X"
- user=> (-> (/ 144 12) (/ 2 3) str keyword list)
- (:2)
- user=> (list (keyword (str (/ (/ 144 12) 2 3))))
- (:2)
- user=> (-> (/ 144 12))
- 12
- user=> (-> (/ 144 12) (/ 2 3))
- 2
- user=> (-> (/ 144 12) (/ 2 3) str)
- "2"
- user=> (-> (/ 144 12) (/ 2 3) str keyword)
- :2
- user=> (-> (/ 144 12) (/ 2 3) str keyword list)
- (:2)
- user=> (/ (/ 144 12) 2 3)
- 2
- user=> (str (/ (/ 144 12) 2 3))
- "2"
- user=> (keyword (str (/ (/ 144 12) 2 3)))
- :2
- user=> (list (keyword (str (/ (/ 144 12) 2 3))))
- (:2)
->>: 后面的函数迭代使用之前的函数结果作为最后一个参数,返回最后一次函数调用的值,试看下面两个语句:
- user=> (-> 10 (/ 3)) ; 10/3 10作为/函数第一个参数
- 10/3
- user=> (->> 10 (/ 3)) ; 3/10 10作为/函数最后一个参数
- 3/10
- user=> (eval (str "(println 1)")) ;str函数返回字符串
- "(println 1)"
- user=> (read-string "(println 1)") ;而read-string函数用于从字符串中读取对象
- (println 1)
- user=> (eval (read-string "(println 1)"))
- 1
- nil
apply函数: apply 把给定的集合里面的所有元素一次性地给指定的函数作为参数调用,然后返回这个函数的返回值。可以把apply看作是SQL里面的聚合函数,如下:
- user=> (apply + [1 2 3 4])
- 10
三、函数检查
fn?: fn?用于检查给定的参数是否为函数,是返回true,否则返回false,如:
- user=> (fn? #("test"))
- true
- user=> (fn? 1)
- false
- user=> (fn? nil)
- false
- user=> (fn? +)
- true
- user=> (fn? mod)
- true
- user=> (fn? rem)
- true
- user=> (fn? =)
- true
- user=> (fn? with-precision)
- java.lang.Exception: Can't take value of a macro: #'clojure.core/with-precision (NO_SOURCE_FILE:32)
- user=> (fn? min)
- true
- user=> (fn? >=)
- true
参考推荐:
clojure 学习
Clojure 学习入门(6)- 函数定义相关推荐
- Clojure 学习入门(6)—— 函数定义
一.创建函数: fn: fn是一个宏,用于定义一个简单的函数,如下: user=> (fn [] "hello") #<user$eval375$fn__376 us ...
- 【python教程入门学习】Python函数定义及传参方式详解(4种)
这篇文章主要介绍了Python函数定义及传参方式详解(4种),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧 一.函数初识 1.定 ...
- Clojure 学习入门(18)—— 数据类型
如何表示和处理数据 Clojure是一种动态类型语言,这意味着你在程序中永远不需要明确定义符号.函数.或者参数的数据类型.但是,所有的值仍然有一个类型.字符串时是字符串,数字是数字,列表是列表,等等. ...
- Python学习笔记 - 探索函数定义和使用
大家好,我是Mr数据杨,你们有没有读过<三国演义>呢?没错,将以这个经典的古代战争史诗为引,来探索Python的诸多神奇之处. 首先来说说函数的重要性.诸葛亮一生献出了不少锦囊妙计,这些计 ...
- Clojure 学习入门(13)- binding
Clojure里面是不支持变量的.Binding跟变量有点像,但是在被赋值之前是不允许改的,包括:全局binding, 线程本地(thread local)binding, 以及函数内的本地bindi ...
- Clojure 学习入门(16)- 正则表达式
一.创建正则表达式 re-pattern函数: 函数 (re-pattern) 接受一个字符串参数,返回一个正则表达式样式(java.util.regex.Pattern类的实例).这个样式能用于 ...
- Clojure 学习入门(15)- 条件判断
一.标准的流程控制 if: 将一个判断表达式作为它的第一个参数进行求值.如果求值为true,那么就返回它的第二个参数(相当于"then"子句)的求值结果.如果结果为false( ...
- Clojure 学习入门(14)- 循环控制
Clojure 基于函数的流程控制 repeatedly 字面意思为重复函数.一般的用法如下: user=> (repeatedly 5 #(rand-int 11)) (6 8 2 6 6) ...
- Clojure 学习入门(11)- 宏 macro
clojure macro宏在运行之前机械展开,定义宏相当于给语言增加新特性,写宏的*原则*: 能写成函数就不要用宏(因为写宏没有写函数简单直观,容易写错,需要先在 REPL 中测试一番) 只有不得 ...
最新文章
- python 怎样让 print 打印的结果不换行
- MySQL 高频 100 问
- 并发编程:原子性问题,可见性问题,有序性问题。
- Java HashSet源码解析
- linux --- 基础指令
- 2019年度年中回顾总结_我的2019年回顾和我的2020年目标(包括数量和收入)
- 数据链路层(学习笔记)
- Java的位运算符具体解释实例——与(amp;)、非(~)、或(|)、异或(^)
- jvm 初始化之 cinit , init
- android return 如何跳出两个循环_PHP跳出循环的方法
- 【转】opencv 配置
- CleanMyMac X2021专业苹果电脑系统优化工具
- 基于51单片机智能车流量检测车量统计系统设计
- mybatis中selectOne方法分析
- der解码规则_[转] DER编码和ASN.1
- linux glog使用
- 聊一聊前端性能优化 CRP
- p73 应急响应-WEB 分析 phpjavaweb自动化工具
- h5 ios中软键盘弹起后 fixed定位失效
- 你是开发工程师、程序员还是码农?