4

I am new to Functional Programming and Clojure, so I am not really sure about what to do for a project at University. The project should show the advantage of Clojure STM for banking transactions (Transfer of money from account A to account B). So I plan to proceed this way:

  1. define initial data, like a matrix of Refs or something better
  2. generate random operations to execute: [ random-account-source-id(0, N_MAX) , random-account-destination-id(0, N_MAX), random-money (0, 1000) ]
  3. insert the transaction into the data structure
  4. Sync transfer of money from source-id to destination-id for all the insertions in the matrix, such as:
    
    for i=0; i lt N; i++;
        synchronize: transfer (matrix[i].source,matrix[i].dest,matrix[i].money)
    

I'm not sure about this, then, maybe:

(defn do-all[]
  (dosync
    (when (pos? N)
      (transfer (get matrix [pos 1], get matrix [pos 2], get matrix [pos 3])))))
The Unfun Cat
  • 29,987
  • 31
  • 114
  • 156
nuvio
  • 2,555
  • 4
  • 32
  • 58

2 Answers2

6

Represent the account with a Ref i.e a Ref for each account and perform the money transfer operation in a dosync operation. Also make sure you dont do any side-effect operation (other than on those Refs) in the dosync operation as it may be retried in case of a conflict while updating refs.

Update: In case you will have the number of accounts fixed then you could use ref of vectors where each ref in the vector is an account and each account is identified by the index in the vector.

Ex:

(def total-accounts 100)
(def accounts (vec (map (fn [_] (ref 100)) (range total-accounts))))

In case you have to dynamically add new accounts and identify them by name then you can use hash map where key is the account id (unique value) and value is the Ref for account balance. You will need to wrap this map in a Ref in case you want to do concurrent operations for adding/removing accounts from multiple threads.

Ankur
  • 33,367
  • 2
  • 46
  • 72
  • thanks very much for your answer, but I am not sure what you mean...could you put an example? I mean, I can handle a small number (let's say 2) of accounts creating a ref for each one and than I know how to operate on them, like: (def account-1 (ref 1000)) (def account-2 (ref 1000)) ...and then... (transfer-function account-1 account-2 100) (transfer-function account-2 account-1 100) But what I really would like to do is to manage a large number (an input N number of accounts) and dynamically create a structure that could work on it synchronously under STM... – nuvio Mar 03 '12 at 16:03
4

You might be interested in this example of Clojure's STM used for banking transactions which I posted in response to another question.

Community
  • 1
  • 1
mikera
  • 105,238
  • 25
  • 256
  • 415
  • How would you put in a loop your function: "(transfer-from-all [(accounts 0) (accounts 1) (accounts 2)] (accounts 3) 5)" something like...I don't really know the sintax (transfer-from-all dotimes [i NMAX] [(accounts i) inc i)" – nuvio Mar 04 '12 at 23:43
  • 1
    (doseq [x collection] (transfer-from x ....)) is probably the easiest way to loop over every element in a collection if you want to perform an imperative action on each. – mikera Mar 05 '12 at 00:41