`
Dead_knight
  • 浏览: 1202261 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
博客专栏
752c8642-b795-3fe6-946e-a4e845bffdec
Spring Securi...
浏览量:240602
33caa84e-18a6-3036-a82b-6e2106a4de63
clojure专题
浏览量:49055
E17ca077-44df-3816-a3fe-471c43f6e1e5
WebLogic11g
浏览量:237060
社区版块
存档分类
最新评论

clojure-基本语法-函数定义

阅读更多
一、创建函数:
fn:
fn是一个宏(后面进行详细描述),用于定义一个简单的函数,如下:
user=> (fn [] "hello")
#<user$eval375$fn__376 user$eval375$fn__376@eabd2f>
user=> ((fn [] "hello"))
"hello"
user=> ((fn [x] x) "hello") ; 带参数
"hello"

简短的函数可以使用#(),%表示唯一的参数;%1、%2 ..表示第1、2、..个参数;%&表示所有参数,如下:
user=> (#(/ % 3) 4);结果为3/4
4/3
user=> (#(/ %2 %1) 3 4);结果为3/4
4/3
user=> (#(apply / %&) 3 5 7);结果为3/5/7
3/35

下面是几个定义函数的例子:
user=> ((fn [x] (+ 1 x)) 3);一个参数,完成加一的功能
4
user=> (#(+ 1 %) 3);使用#符号完成加一的功能
4
user=> ((fn [x y] (* x y)) 3 4);两个参数,实现乘积的功能
12
user=> (#(* %1 %2) 3 4);使用#符号完成两个参数乘积的功能
12


defn:
defn 宏用来定义一个函数。它的参数包括一个函数名字,一个可选的注释字符串,参数列表,然后一个方法体。而函数的返回值则是方法体里面最后一个表达式的值。所有的函数都会返回一个值, 只是有的返回的值是nil。
user=> (defn f1 [] "hello");定义无参函数
#'user/f1
user=> (f1)
"hello"
user=> (defn f2 [x] (format "hello %s" x));定义一个参数函数
#'user/f2
user=> (f2 "girl")
"hello girl"
user=> (defn f3 [x y] (+ x y));定义两个参数相加的函数
#'user/f3
user=> (f3 2 4)
6
user=> (defn f4 "f4 function" [] (println "f4 function"));带注释的函数
#'user/f4
user=> (f4)
f4 function
nil
user=> (doc f4);通过doc查看函数注释信息
-------------------------
user/f4
([])
  f4 function
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


defn-:
defn-与defn功能一致,都是用于定义函数的,但是defn-定义的函数作用域是私有的,而defn定义的函数是公有的,如下:
user=> (ns test1);ns的意思是切换到指定的命名空间,如果不存在,则新建该命名空间
nil
test1=> (defn- foo [] "world");定义私有函数foo,返回字符串world
#'test1/foo
test1=> (defn bar [] (str "hello " (foo)));定义公有函数bar,并调用私有函数foo
#'test1/bar
test1=> (foo);当前命名空间内调用foo函数
"world"
test1=> (bar);当前命名空间内调用bar函数
"hello world"
test1=> (ns test2);切换到test2命名空间中
nil
test2=> (test1/bar);调用test1命名空间的bar函数,返回成功
"hello world"
test2=> (test1/foo);调用test1命名空间的foo函数,出现异常,提示test1的foo函数不是公开的
CompilerException java.lang.IllegalStateException: var: #'test1/foo is not public, compiling:(NO_SOURCE_PATH:1)


组合函数comp:
形如:
((comp f1 f2 .. fn) arg1 arg2 .. argn)

就是对参数从右到左组合执行所有函数,可以转变为:
(f1 (f2 (.. (fn arg1 arg2 .. argn))))

举例如下:
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)

就是执行:
(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=>(first (.split (.replace (.toUpperCase "a b c d") "A" "X") " "))
user=>"X" 
user=> (-> "a b c d" .toUpperCase (.replace "A" "X") (.split " ") first)
user=>"X" 

这样调用的好处是更少的(),也更接近于scala的习惯。
(-> (/ 144 12) (/ 2 3) str keyword list)
(list (keyword (str (/ (/ 144 12) 2 3))))

上面两句结果一样。

->>:
后面的函数迭代使用之前的函数结果作为最后一个参数,返回最后一次函数调用的值
分下下面两个语句:
(-> 10 (/ 3)) ; 10/3  10作为/函数第一个参数
(->> 10 (/ 3)) ; 3/10  10作为/函数最后一个参数


eval:
eval解析表达式数据结构(不是字符串),并返回结果。
user=> (eval (str "(println 1)"));str函数返回字符串
"(println 1)"
user=> (read-string "(println 1)");而read-string函数用于从字符串中读取对象
(println 1)
user=>  (eval (read-string "(println 1)"))
1


apply函数:
apply 把给定的集合里面的所有元素一次性地给指定的函数作为参数调用,然后返回这个函数的返回值。可以把apply看作是SQL里面的聚合函数,如下:
user=> (apply + [1 2 3 4])
10


三、函数检查
fn?:
fn?用于检查给定的参数是否为函数,是返回true,否则返回false,如:
user=> (fn? #("test"))
true
user=> (fn? +)
true
user=> (fn? 1)
false
分享到:
评论

相关推荐

    clojure-must-watch-源码.rar

    了解Clojure的基础语法,如S-expressions(符号表达式)、宏、动态类型以及如何定义和调用函数,是深入研究源码的前提。 2. **数据结构**:Clojure提供了多种内置数据结构,如列表、向量、映射、集合和范围。理解...

    clojure-basics-源码.rar

    例如,你可能会看到如何使用`defn`定义函数,`let`创建局部变量,或者如何使用`map`函数对集合进行操作。此外,源码可能还涉及到Clojure的并发模型,如`swap!`函数用于原子性更新状态,以及`future`或`promise`来...

    clojure-mxnet:MXNET的Clojure软件包

    1. **API设计**:Clojure-MXNet提供了与MXNet原生API相匹配的Clojure接口,允许用户用Clojure代码定义神经网络结构、加载和预处理数据、训练模型以及评估性能。这包括了层的创建(如卷积层、全连接层)、损失函数的...

    clojure-rust:Clojure转换为Rust编译器

    - **函数和高阶函数**:Clojure的fn和defn需要转换为Rust的函数定义,同时处理map、filter等高阶函数的转换。 - **多态和接口**:Clojure的协议和记录可能需要映射到Rust的trait和实现。 - **并行和并发**:Clojure...

    clojure-deps-edn:基于deps.edn的项目的有用配置和别名的集合

    它采用Clojure语法,使得配置文件本身可读性强,易于理解和维护。例如,你可以这样声明一个依赖: ```clojure {:deps {org.clojure/clojure {:mvn/version "1.10.3"}} :aliases {"dev" [:require [clojure.java....

    mr-clojure-exploded:MixRadio leiningen模板的结果代码

    3. 闭包和函数式编程:Clojure鼓励使用纯函数和不可变数据结构,这些特性使得代码更易于理解和测试,同时也提高了并行处理的效率。 4. 组件系统(Component):Clojure社区中流行的一种架构模式,它帮助开发者设计...

    clojure-shopshop:一日研讨会的基本Clojure培训材料

    3. **Examples**:示例代码,用于演示Clojure的特性,例如函数定义、数据处理、递归、多态等。 4. **Exercises**:练习题目,供学员在实践中巩固所学知识,可能涵盖基础语法、数据结构操作、问题解决等。 5. **...

    clojure-misc:Clojure练习-不使用

    这个“clojure-misc”项目似乎是一系列Clojure语言的练习,旨在帮助学习者加深对Clojure语法、函数式编程特性和常用库的理解。 1. **函数式编程基础**: - Clojure鼓励使用函数来解决问题,避免使用副作用,这有助...

    clojure-dependency-update-action:一个简单的GitHub Actions,用于为过时的工具创建请求请求。

    Clojure 是一种基于Lisp的函数式编程语言,它运行在Java虚拟机(JVM)上,具有强大的元编程能力和动态性。在这个场景中,"clojure-dependency-update-action"是一个专门为Clojure项目设计的GitHub Actions。GitHub ...

    clojure-by-example:针对Clojure的程序员的研讨会

    1. **基础语法**:介绍Clojure的基本语法,如S表达式、符号、数字、字符串、布尔值等,并演示如何在Clojure中读写这些基本类型。 2. **函数与高阶函数**:Clojure的函数是第一类公民,可以作为参数传递,也可以作为...

    using-clojure-for-web-apps

    Compojure是基于Ring的一个路由库,它使用简洁的语法定义URL映射,便于构建复杂的Web应用结构。 Reagent是ClojureScript中的一个React绑定库,它将Clojure的数据驱动哲学带入前端开发。Reagent的组件函数接收...

    learning-clojure-address-book:我在@JarrodCTaylor 精彩教程系列中取得的进展,关于如何使用 clojure 构建地址簿

    例如,`(defn name [params] body)` 是定义函数的语法,`name`是函数名,`params`是参数列表,`body`是函数体。Clojure支持函数式编程,这意味着我们可以将函数视为第一类公民,可以赋值给变量、作为参数传递和返回...

    boston-clojure-hoplon-demo

    项目中会包含各种Clojure函数的使用,例如map、reduce、filter等高阶函数,以及defn定义函数、let局部变量绑定等基本语法。 2. **Hoplon模板**:Hoplon允许开发者用Clojure语法编写HTML,这称为Hoplon DSL(领域...

    clojure-examples:杂项 clojure 示例

    Clojure 是一种基于 Lisp 语法的函数式编程语言,它运行在 Java 虚拟机(JVM)上,充分利用了 JVM 的性能和生态系统。在这个名为 "clojure-examples" 的项目中,我们看到一系列的 Clojure 示例代码,旨在帮助开发者...

    clojure-mode:Emacs对Clojure(Script)编程语言的支持

    1. **语法高亮**:Clojure mode 提供了对 Clojure 语法的高亮显示,包括关键词、符号、字符串、注释等,帮助开发者更好地识别代码结构。 2. **自动缩进**:根据 Clojure 语言规范,模式可以自动进行代码缩进,保持...

    clojure-anglican

    Clojure强调 immutability(不可变性)、concurrency(并发)和functional programming(函数式编程)原则。其语法受到Lisp家族语言的影响,采用括号表示表达式结构。 Clojure的生态系统丰富多样,包括用于Web开发...

    todo-backend-clojure-reitit:Todo-Backend API规范的ClojureReititnext.jdbc实现

    Clojure是一种现代的、动态类型的函数式编程语言,它运行在Java虚拟机(JVM)上,同时也支持JavaScript和.NET平台。Clojure的设计目标是提高开发者的生产力,通过其简洁的语法和强大的并行处理能力,使得开发者能够...

    clojure-tensorflow-interop:如何在Clojure中运行TensorFlow

    Clojure,一种基于Lisp的函数式编程语言,以其简洁的语法和强大的元编程能力受到许多开发者喜爱。而TensorFlow,作为Google开发的开源机器学习框架,已经在人工智能领域占据了重要的位置。将这两者结合,可以为数据...

    clojure-workshop-guide:使用Clojure进行功能编程的材料

    这个指南旨在帮助参与者逐步理解Clojure的基本概念、语法和特性,通过一系列的研讨会活动,深入掌握Clojure在实际开发中的应用。下面我们将详细探讨Clojure的核心知识点及其在实践中的应用。 首先,Clojure是基于...

    clojure-style-guide:コミュニティによるClojureスタイルガイド

    5. **函数定义与参数** - 长参数列表应考虑使用映射或其他数据结构来传递,以提高可读性。 - 对于无副作用的纯函数,参数应尽可能少,以降低认知负担。 6. **宏的使用** - 宏应当谨慎使用,因为它们可以改变代码...

Global site tag (gtag.js) - Google Analytics