clojure 新手指南(7):定义函数

前几章中,咱们用了一种比较迂回的方式建立函数:把匿名函数绑定到一个变量上。实际上,clojure提供了一个更好的方式作同一件事情。“defn” 这个函数就是专门用于定义函数的。 java

在咱们使用defn以前,咱们再回顾一下以前咱们怎么使用def来建立函数的,而后咱们使用defn来作同一件事情对比一下。 shell

;;使用def
=>(def alphabet-length (fn [ ](count alphabet)))
#'user/alphabet-length

=>(alphabet-length)
26

;;使用defn
=>(defn alphabet-length [ ](count alphabet))
#'user/alphabet-length

=>(alphabet-length)
26
上面两种方式作的都是同一件事情。可是defn能作更多的事情。下面是defn定义函数的一个脚手架:

[1] (defn name                    函数名
 [2]   "description"               函数描述 (可选)
 [3]   {metadata}                  元数据   (可选)
 [4]   [arguments]                 参数列表 
 [5]   body-of-expressions...)     函数体
上面咱们能够看出,defn在定义函数时能够提供更多的信息。

下面让咱们用上面这些信息定义一个函数: express

=>(defn select-random
    "从一个列表中随机返回一个元素"
    {:added "1.2"}  ;; 元数据
    [options]
    (nth options (rand-int (count options))))
#'user/select-random

(count options) 用于计算options包含的元素数量。(nth options x) 用于从options中获取第x个元素(从0开始,相似java中的list的get方法) 编程

咱们以前说过clojure是lisp的一种方言。lisp 是 “List  Processor”的缩写,就是列表解析的意思,使用列表来表示全部的东西(S表达式)。从咱们写的代码也能够看出,整个代码结构就是一个嵌套的列表。如今让咱们用列表结构来保存数据: app

=>(list "growl" "lick" "jump")
("growl" "lick" "jump")
咱们以前定义的函数select-random须要的参数正是一个列表,正好咱们就能够用来测试:
=>(select-random (list "growl" "lick" "jump"))
"jump"

=>(select-random (list "growl" "lick" "jump"))
"growl"
运行一切正常,说明select-random没什么问题。咱们能够在一个新的函数中来使用它。咱们来建立一个用于问候的函数greeting。
=>(defn greeting
    "Composes a greeting sentence. Expects both the name of a greeter
     and the name of whom is to be greeted for arguments. An approach
     and an action are randomly selected."
    {:added "1.2"}
    [greeter whom]
        ;;str 用于组装字符串
        (str greeter  " greeted " whom " with a "
        (select-random (list "ferocious" "wimpy" "precarious" "subtle")) " "
        (select-random (list "growl" "lick" "jump")) "!")) 
#'user/greeting

=>(greeting "Jon" "Thaddeus")
"Jon greeted Thaddeus with a wimpy growl!"

=>(greeting "Jon" "Thaddeus")
"Jon greeted Thaddeus with a precarious lick!"

固然,上面的问候函数不是很完美。咱们能够把问候语句单独提出来。 dom

=>(def approaches (list "ferocious" "wimpy" "precarious" "subtle"))
'user/approaches

=>(def actions (list "growl" "lick" "jump"))
#'user/actions
而后在greeting中使用绑定的列表:
=>(defn greeting
    "Composes a greeting sentence. Expects both the name of a greeter
     and the name of whom is to be greeted for arguments. An approach
     and an action are randomly selected."
     {:added "1.2"}
     [greeter whom]
     (str greeter  " greeted " whom " with a "
        (select-random approaches) " "
        (select-random actions) "!"))
#'user/greeting
如今可读性好多了吧,把变化的部分单独抽象出来这个原则对于函数式编程也是通用的哦。这样咱们就能够在不修改函数的状况下改变问候语句了。

至于函数定义中的元数据有什么做用,暂时保密,后面会单独来说。 函数式编程

相关文章
相关标签/搜索