Reputation: 959
I'm new with Clojure and I'm working on creating a simple bank account function that returns a closure. I have figured out how to initialize the variables, but I can't seem to figure out how to manipulate the balance. I would like to create a :withdrawal and :deposit to perform their respective functions, but I can't seem to figure out how.
(defn account
[name initial-balance password]
(fn [a & args]
(condp = a
:name name
:balance initial-balance
:authenticate (= password (first args)))))
Upvotes: 0
Views: 164
Reputation: 2600
Here's another approach which still represents the account as a closure but doesn't mutate balance
. Instead, deposit
and withdraw
return a new account closure.
(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)))))
Since e.g. (person :deposit 50)
returns a new closure rather than the new balance you would need to follow it up with a :balance
call/message to see what the resulting balance was.
(def person (account "name" 100 "password"))
(person :deposit 50) ; returns a new closure
;=> #<user$account$fn__85647 user$account$fn__85647@884327>
(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
Upvotes: 2
Reputation: 33019
The Clojure idioms usually discourage mutable state. When you do want to mutate something like your bank account balance, the usual way to do that would be with a thread-safe atom
. Here's an example:
(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))))))
Upvotes: 3