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

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

在我们使用defn之前,我们再回顾一下之前我们怎么使用def来创建函数的,然后我们使用defn来做同一件事情对比一下。

;;使用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在定义函数时可以提供更多的信息。

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

=>(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表达式)。从我们写的代码也可以看出,整个代码结构就是一个嵌套的列表。现在让我们用列表结构来保存数据:

=>(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!"

当然,上面的问候函数不是很完美。我们可以把问候语句单独提出来。

=>(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
现在可读性好多了吧,把变化的部分单独抽象出来这个原则对于函数式编程也是通用的哦。这样我们就可以在不修改函数的情况下改变问候语句了。

至于函数定义中的元数据有什么作用,暂时保密,后面会单独来讲。


转载于:https://my.oschina.net/clopopo/blog/142589

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值