2013-11-21 131 views
0

我是新的Clojure,我正在创建一个简单的银行账户函数,它返回一个闭包。我已经想出了如何初始化变量,但我似乎无法弄清楚如何操纵平衡。我想创建一个:撤回和:存款来执行各自的功能,但我似乎无法弄清楚如何。操作Clojure关闭?

(defn account 
    [name initial-balance password] 
    (fn [a & args] 
    (condp = a 
     :name name 
     :balance initial-balance 
     :authenticate (= password (first args))))) 
+0

相反condp'的',你可能需要使用['case'(http://clojuredocs.org/clojure_core/clojure.core/case),这是一个小更简洁(但只适用当你只是比较编译时常量,如关键字)。 – DaoWen

回答

3

Clojure成语通常不鼓励可变状态。当你想要改变你的银行账户余额时,通常的做法是使用线程安全的atom。这里有一个例子:

(defn account 
    [name initial-balance password] 
    (let [balance (atom initial-balance)] 
    (fn [a & args] 
     (case a 
     :name name 
     :balance @balance 
     :deposit (swap! balance + (first args)) 
     :withdraw (swap! balance - (first args)) 
     :authenticate (= password (first args)))))) 
+0

所以如果我创建一个这样的人, '(def person(account“name”1000“password”))' 如何使用':deposit'?我试过 '(person:deposit 200)',我收到一个错误。 – Busch

+1

@Busch,你有什么错误?发布的代码为我工作。尝试再次评估'account',可能是旧版本卡住了。 – jbm

+0

@Busch - 我在发布之前测试了代码,因此它应该可以工作。我也试过将我的代码粘贴到新的REPL中,然后从您的评论中粘贴代码,并且它工作正常。我认为jbm是对的。您应该在新的REPL会话中再次尝试。 – DaoWen

2

这里是另一种方法,仍然代表帐户作为封闭,但不会改变balance。相反,depositwithdraw会返回新的帐户关闭。

(defn account 
    [name balance password] 
    (fn [msg & args] 
    (case msg 
     :name name 
     :balance balance 
     :deposit (account name (- balance (first args)) password) 
     :withdraw (account name (+ balance (first args)) password) 
     :authenticate (= password (first args))))) 

由于例如(person :deposit 50)返回一个新的结算信息,而不是新的余额,您需要使用:balance来电/信息来查看结果余额是多少。

(def person (account "name" 100 "password")) 

(person :deposit 50) ; returns a new closure 
;=> #<user$account$fn__85647 [email protected]> 

(person :balance) ; our original `person` still has its original balance 
;=> 100 

((person :deposit 50) :balance) ; but a new closure can have a new balance 
;=> 150 
+0

+1这里也有很好的功能方法。即使OP正在寻找具有变异的东西,希望看到这个功能性示例将帮助他更多地考虑下一次使用不可变数据结构。 – DaoWen