Can I create mutable state inside Clojure records? - clojure

I am considering using Clojure records to map to changing entities in my program. Are they mutable? Or do you need to use extra refs within the records? I am a little confused about this

It's well worth watching Rich Hickey's fantastic video on identity and state.
Records are designed to be immutable and store the state of something as a value.
To model the state of a changing entity, I'd recommend using a ref that refers to an immutable value that represents the current state. You can use records for the immutable state, but often it's simpler just to use a simple map.
A simple example, where the mutable state is a scoreboard for a game:
; set up map of current scores for each player
(def scores
(ref
{:mary 0
:joe 0 }))
; create a function that increments scores as a side effect
(defn add-score [player amount]
(dosync
(alter scores update-in [player] + amount)))
; add some scores
(add-score :mary (rand-int 10))
(add-score :joe (rand-int 10))
; read the scores
#scores
=> {:mary 6, :joe 1}

I have found that I much more commonly put records in refs than refs in records. mikira's advice to use a simple map sounds very good.
Start with a map and switch to something less flexable when you have to.

Related

How to return hiccup as a list/vector

I am passing a vector of hiccup to a funtion that just wraps it in more hiccup, but it does not return it as I would expect.
Here's an example of what I mean:
(defn wrap-fn
[input]
[div.content-box
[input]])
(defn main-fn
[vector-of-hiccup]
(foreach [hiccup from vector-of-hiccup]
(wrap-fn hiccup-from-list)))
How do I implement the made up foreach loop above?
I've tried to use 'apply' to apply the wrap-fn to each of the vector params but it only returns the first element wrapped. I've tried to creating all sorts of loops and I have similar levels of success.
I'm sure there is a way to do this, please help me find one that works.
You need something like this:
(defn wrap-fn
[input]
[:div.content-box
[input]]) ; <= you may not want to wrap `input` in a vector.
(defn main-fn
[vector-of-hiccup]
(vec
(for [item vector-of-hiccup]
(wrap-fn item))))
Note the : in :div. Hiccup vectors always start with a keyword. Also, since for returns a lazy sequence, you should convert it into a vector with vec.
Also, depending on your situation, you may want to have input instead of [input] under the :div.content-box.
See the Documentation section of the clj-template project for valuable learning information.

Dynamic variables in Clojure libraries

TL;DR: Is the following a good pattern for a library?
(def ^{:dynamic true} *var*)
(defn my-fn [{:keys [var]}]
(do-smth (or var *var*)))
--
Say I want to write a sentiment analysis library.
Is it good design in get-sentiment fn to accept optional sentiment labels but provide default one as dynamic var?
(def ^:dynamic *sentiment-level-labels*
["Very Negative" "Negative" "Neutral" "Positive" "Very Positive"])
;;...
(defn get-sentiment-scores
"Takes text and gives back a 0 to 4 sentiment score for each sentences."
[text]
;;...)
(defn get-sentiment
"Gives back a sentiment map with sentences scores,
average score, rounded score and labeled score.
Can accepts custom sentiment level labels under :labels opt."
[text & {:keys [labels]}]
(let [scores (get-sentiment-scores text)
average-score (get-average scores)
rounded-score (Math/round average-score)
label (get (or labels *sentiment-level-labels*) rounded-score)]
{:scores scores
:average-score average-score
:rounded-score rounded-score
:label label}))
Clojure library coding standards official page says:
If you present an interface that implicitly passes a parameter via
dynamic binding (e.g. db in sql), also provide an identical interface
but with the parameter passed explicitly.
https://dev.clojure.org/display/community/Library+Coding+Standards
In my example, I provided only one interface but with opt argument.
Is this okay? Are there better ways to handle this?
Thank you!
Dynamic vars are full or pitfalls. They push your API code towards implicit environmental coupling, and often force your calling code to add a lot of (binding ...) clauses, which kind of defeats the purpose of concision for using Dynamic vars in the first place. They also lead to tricky edge cases if control is passed from one thread to another.
In your case, I would recommend simply passing the labels in a params map argument:
(def default-sentiment-level-labels
["Very Negative" "Negative" "Neutral" "Positive" "Very Positive"])
(defn get-sentiment
"Gives back a sentiment map with sentences scores,
average score, rounded score and labeled score.
Can accepts custom sentiment level labels under :labels opt."
[text {:as params, :keys [labels] :or {labels default-sentiment-labels}}]
...))
Note that the usage of a map can be interesting, because a map is opaque to intermediaries: you can have various components of your algorithm read only from the params map the keys that concern them.

Opportunity to use a transducer?

Using Clojure, I'm pulling some data out of a SQLite DB. It will arrive in the form of a list of maps. Here is an abbreviated sample of what the data looks like.
(
{:department-id 1 :employee-firstname "Fred" :employee-lastname "Bloggs"}
{:department-id 1 :employee-firstname "Joe" :employee-lastname "Bloggs"}
{:department-id 2 :employee-firstname "John" :employee-lastname "Doe"}
...
)
I would like to reshape it into something like this:
(
{:department-id 1 :employees [{:employee-firstname "Joe" :employee-lastname "Bloggs"} {:employee-firstname "Fred" :employee-lastname "Bloggs"}]}
{:department-id 2 :employees [{:employee-firstname "John" :employee-lastname "Doe"}]
...
)
I know I could a write a function that dealt with the departments and then the employees and "glued" them back together to achieve the shape I want. In fact I did just that in the REPL.
But I've heard a bit about transducers recently and wondered was this an opportunity to use one.
If it is, what would the code look like?
I'll have a go, but like many of us, I'm still wrapping my head around this as well.
From my reading on transducers, it would seem the real benefit is in avoiding the need to create intermediate collections, thereby increasing efficiency. This means that to answer your question, you really need to look at what your code will be doing and how it is structure.
For example, if you had something like
(->>
(map ....)
(filter ..)
(map ..)
(map ..))
the functions are being run in sequence with new collections being created after each to feed into the next. However, with transducers, you would end up with something like
(->>
(map ...)
(map ..)
(filter ..)
(map ...))
where the functions being applied to the data are applied in a pipline fashion on each item from the original collection and you avoid the need to generate the intermediate collections.
In your case, I'm not sure it will help. This is partially because I don't know what other transformations you are applyinig, but mainly because what you are wanting requires a level of state tracking i.e. the grouping of the employee data. This is possible, but I believe it makes it a little harder.

Large Data Structure in Clojure STM for Banking Transactions LOOP

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:
define initial data, like a matrix of Refs or something better
generate random operations to execute: [
random-account-source-id(0, N_MAX) ,
random-account-destination-id(0, N_MAX), random-money (0, 1000) ]
insert the transaction into the data structure
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])))))
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.
You might be interested in this example of Clojure's STM used for banking transactions which I posted in response to another question.

Can Clojure's STM's history of values be accessed?

Given that the STM holds a history of say 10 values of refs, agents etc, can those values be read ?
The reason is, I'm updating a load of agents and I need to keep a history of values. If the STM is keeping them already, I'd rather just use them. I can't find functions in the API that look like they read values from the STM history so I guess not, nor can I find any methods in the java source code, but maybe I didn't look right.
You cannot access the stm history of values directly. But you can make use of add-watch to record the history of values:
(def a-history (ref []))
(def a (agent 0))
(add-watch a :my-history
(fn [key ref old new] (alter a-history conj old)))
Every time a is updated (the stm transaction commits) the old value will be conjed onto the sequence that is held in a-history.
If you want to get access to all the intermediary values, even for rolled back transactions you can send the values to an agent during the transaction:
(def r-history (agent [])
(def r (ref 0))
(dosync (alter r
(fn [new-val]
(send r-history conj new-val) ;; record potential new value
(inc r)))) ;; update ref as you like
After the transaction finished, all changes to the agent r-history will be executed.