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
如今可讀性好多了吧,把變化的部分單獨抽象出來這個原則對於函數式編程也是通用的哦。這樣咱們就能夠在不修改函數的狀況下改變問候語句了。

至於函數定義中的元數據有什麼做用,暫時保密,後面會單獨來說。 函數式編程

相關文章
相關標籤/搜索