How to create a custom "getter" query in cljs re-frame? - clojurescript

I'm writing a re-frame app that models a board game where I have a board structure containing an array of cells, something like:
{... :board-cells [{:name "cell-1" :material #object} {:name "cell-2" :material #object} ...]}
While re-frame supports the getting of "natural" substructures with a nice keyword syntax like (db :board-cells), I'm getting tired of having to write the entire "drill-down" query every time I want to get a material: (get (nth (db :board-cells) index) :material). This also has the downside of tightly coupling the physical layout of my db to my application logic. What if I decide to change my db structure? Then I have to update ten different spots instead of just one.
Is there a re-frame official way to create a "virtual query" so I can get a material with something like (db :get-nth-mat n), where n is the cell number within the board-cells array? I thought that db.cljs and reg-sub was where I could do this, but it doesn't seem to work. Yes, I can create my own getter:
(defn get-material [db index]
(get (nth (db :board-cells) index) :material))
and call it like (println "mat-4=" (cell/get-material db 4)), but this isn't as convenient or nice as (db :get-nth-mat n)
Many thanks.

db is just a map and this "feature" there has nothing to do with
re-frame, but every map is a function and so are keywords. So when you
do (map something) or (:keyword something) you are actually doing
(get map something) and (get something :keyword).
So there really is no "shortcut" other than accessing/iterating your
data differently (e.g. doseq, for, map, ...) - assuming you are
about to render the grid cell by cell; This way you get rid of the
index based access at all.
Otherwise I'd use a dedicated function like yours, but would rather name
it material-by-idx (it's rather uncommon to name function get and
set like accessors in OO (but there are places for it like e.g.
set for state modification)).
Having properly named, ideally pure, functions, that do one thing
properly is an important building block in functional and Lisp
programming. And often the downside of having to type a bit more can be
mitigated by higher level programming paradigms like threading or partial
application or as last resort, macros.
And you can use get-in to unclutter it a bit:
(defn material-by-idx [db idx]
(get-in db [:board-cells idx :material]))
E.g. you could now in your loop use something like this, if you see
value in that:
(let [mat-at (partial material-by-idx db)]
(mat-at 5))
Btw: The version you are wishing for (db :get-nth-mat n) actually
works (but not as you wish for). It turns into (get db :get-nth-mat
n) (3 argument get), which returns you n if there is no key
:get-nth-mat in db.

Related

Clojure: How to use Mapping with an Anonymous Function?

(defn recurse
[temp total] ;total is: (and true true(and false))
(map (fn [i]
(cond
(seq? i) (println "");If total is not a single parenthesis (single sequence), recur until it is
(= i 'and) (System/exit 0) ;I want this to be called only when the **second** "and" is called
:else (println "This should never print I think")
))
idealreturn)
)
I want (System/exit 0) to be called only when the second "and" is detected in total and not before. How would I go about doing this?
You are on the right track with mapping a function over the data to transform it. There are a couple of ways to get what you are looking for:
Don't use map, and use reduce instead. Reduce is for building up state over time. So you could reduce it into an expression, and each time you encounter an and, you look to see if there is already an and in the result you are building up, and if that and is already there, call the exit.
Have the function you are mapping over the input do only one thing, convert single items into more meaningful things. Then once it is done, pass that result to a second function that checks if it's time to exit.
Giving each thing one responsibility makes for code that's much easier to write, and composing them afterwords is efficient and easy. It's also much easier on you later when you come back to work on the code later.

Clojure/Clojurescript: Argument to resolve must be a quoted symbol

I'm attempting to use a string saved in a variable to call a function like so:
(defn update-product-list [] "Test")
(defn handle-state-change [action]
((resolve (symbol action))))
(handle-state-change "update-product-list")
However, this gives me the following error: Assert failed: Argument to resolve must be a quoted symbol
I've also tried changing the above line to:
((resolve (quote (symbol action))))
But this still gives an error. I also tried changing it just to:
((resolve 'action))
But this gives a different error I don't quite understand: js/action is shadowed by a local. I don't want to override the function just call it. Not sure where I'm going wrong. I've looked at a few examples, but can't see to pin it down.
ClojureScript supports :advanced optimization, in which Google Closure Compiler will rename, inline, or eliminate (unused) functions in order to implement minification. In short, the name of the function you want to look up will, in general, simply no longer exist under :advanced.
Because of this, ClojureScript's resolve is a compile-time facility (a macro requiring a literal quoted symbol).
If you are using :simple or self-hosted ClojureScript, more options are available to you because the support needed persists into runtime. For example Planck has a planck.core/resolve that behave's like Clojure's resolve. A similar approach is possible in Lumo, and similar facilities can be fashioned if using :simple.
In general though, given :advanced, if you need to map strings to a set of functions, you need to somehow arrange to have a static mapping constructed at compile time to support this (the set of functions must be known a priori, at compile time).
If you have a namespace (the name of which is statically known at compile time) which defines functions that need to be dynamically called via strings, you could consider making use of ns-publics:
cljs.user=> (ns foo.core)
foo.core=> (defn square [x] (* x x))
#'foo.core/square
foo.core=> (in-ns 'cljs.user)
nil
cljs.user=> (when-some [fn-var ((ns-publics 'foo.core) (symbol "square"))]
(fn-var 3))
9
This will work under :advanced. The mapping constructed by ns-publics is static; built at compile-time. If you have multiple namespaces that need such treatment, you could merge several calls to ns-publics to build a larger map.
The advantage of this approach is that the code involved is pretty short and requires little maintenance. The disadvantage is that it dumps all of the public vars of the namespace (foo.core in this example) into your generated code (and the generated code for vars is somewhat verbose). Another disadvantage is that you need to statically know the namespace(s) involved at compile time.
If you need to further minimize generated code size, you could just build / maintain a simple static map from string to function value as in
(def fns {"square" foo.core/square})
and use it appropriately, keeping it up to date as your codebase evolves.
Another option would be to mark the functions that you need to access using ^:export meta, and then to call those functions using JavaScript interop. For example if you define the function this way
(defn ^:export square [x] (* x x))
then you can use strings / interop to lookup the function and call it at runtime. Here's an example:
((goog.object/getValueByKeys js/window #js ["foo" "core" "square"]) 3)
The use of ^:export and :advanced is covered here. If you know that you are using :simple or less, then you can simply use JavaScript interop to call the functions of interest, without needn't to use ^:export.
Note that there is no general solution that would let you look up a function by name at runtime under :advanced without somehow putting some aspect of that function into your code at compile time. (In fact, if a function is not referenced in a way that Google Closure Compiler can statically, see, the function implementation will be completely eliminated as dead code.) In the above, ns-publics grabs all the vars for a namespace at compile time, rolling your own lookup map sets up static code to refer to the function value, and using ^:export statically arranges to make the name of the function persist into runtime.
You need to use it like this:
((resolve 'inc) 5)) => 6
or, deconstructed a bit:
(let [the-fn (resolve 'inc)]
(the-fn 7))
=> 8
If you have the function name as a string, use the symbol function to convert from string => symbol (from clojuredocs.org):
user=> ((-> "first" symbol resolve) [1 2 3])
1
And, never forget the Clojure CheatSheet!

eval-str in ClojureScript with public structure as a parameter

My problem requires applying custom logical functions to a structure. Those functions are stored in a database as a string. I have data like this:
(def fruits {:apple {:color "red" :ripe? true}
:strawberry {:color "red" :ripe? false}})
And I have this cond check:
"(some (fn [fruit] (-> fruit val :ripe? false?)) fruits)"
Unfortunatelly I can't get this right even though I tried various approaches:
1)
(cljs/eval-str (cljs/empty-state)
"(some (fn [fruit] (-> fruit val :ripe? false?)) my.main/fruits)"
""
{:eval cljs/js-eval}
identity)
This works yet it yields errors:
WARNING: No such namespace: my.main, could not locate my/main.cljs, my/main.cljc, or Closure namespace "" at line 1
WARNING: Use of undeclared Var my.main/fruits at line 1
Also this approach obviously wouldn't work in advanced compilation.
2) I tried to leverage approach that works in Clojure:
((eval
(read-string
"(fn [fruits]
(some (fn [fruit] (-> fruit val :ripe? false?)) fruits))"))
fruits)
I can't see why this wouldn't work in advanced compilation. Unfortunatelly it simply returns nil every single time.
Is it just me who fails to come up with a solution or is CLJS just not capable of doing that yet?
I suspect your going to have a vary hard time achieving your requirement using
this approach. The big problem is likely going to be due to the way
clojurescirpt needs to be compiled into javascript (using Google closure). You
can probably get it to work doing some clever stuff with externals and using low
level javascript interop and the closure library, but I suspect it will be hard
work.
A couple of alternative approaches which may be worth considering
Store the data in the database in edn format. Using edn, you may be able to
read it into a var and then execute it
Change direction - do you really need to store complete functions or could you
instead define a type of DSL which obtains parameters from the database which
will provide the necessary level of dynamic execution.
Could you have some sort of pre-processing solution i.e. write the function in
clojurescript, but use closure functionality to compile that to javascript and
insert that into the database instead of the raw clojurescript. This would
make the initial storing of the data more complex, but may simplify calling
the dynamic functions at runtime. You could even include some code checks or
validation to reduce the likelihood of code taken from the database doing the
wrong thing.
There are so many risks associated with using totally dynamic code it is almost
never a good solution. Aside from the numerous security issues you have with
this approach, you also have to deal with elegantly handling problems arising
from buggy definitions being inserted into the database (i.e. a buggy function
definition which crashes your app or corrupts data. If you just have to have the
ability to dynamically execute unknown code, then at least edn provides some
additional protection you don't get with eval-str - but really, just don't do
it.
After hours of experiments and struggling with evaluating functions from strings I decided to write DSL.
In database I store string with a map containing these parameters:
:where? - vector containing path to a desired answer.
:what? - answer(s) I'm looking for.
:strict? (optional) - A boolean. If true then answers need to be exactly the same as :what? rule (order doesn’t matter).
Then I just evaluate that simple cljs file. It works both on advanced and none optimization mode.
(defn standard-cond-met? [{:keys [what? where? strict?]
:or {strict? false}}]
(let [answer (get-in answers (conj where? :values))]
(if strict?
(= (sort what?) (sort answer))
(clojure.set/subset?
(set what?)
(set answer)))))

Can I return early (mid-function) in ClojureScript?

I have a function that is iterating over a moderately sized list of strings and is looking through some JSON returned from a server for the existence of a value in the data. The code will be run many times, so I want it to be fast. Is there any way I can return as soon as I find the value I'm looking for?
(defn find-type [js-data-set]
(doseq [type all-type-strs]
(when (aget js-data-set type)
(return true)))) ; is there a way to do this?
The built-in some function will find the first value matching a predicate, which fits this case rather nicely. More generally, you can use loop / recur, though that's rarely the most idiomatic option.
(defn find-type [js-data-set]
(some #(goog.object/get js-data-set %) all-type-strs))

is this swing tablemodel code badly designed?

Context: I have a clojure-based crossword app whose main ui is a JTabbedPane with two tabs, a grid and a clue table. The clue table is a view over a vector of clues, but the vector itself is not the authoritative store of the data, but dynamically generated from a couple of internal data structures via an (active-cluelist) function, triggered by the clue tab being selected.
So this is the implementation of the clue table:
(def cluelist [])
(def update-cluelist)
(def model)
(defn make []
(let [column-names ["Sq" "Word" "Clue"]
column-widths [48 200 600]
table-model (proxy [AbstractTableModel] []
(getColumnCount [] (count column-names))
(getRowCount [] (count cluelist))
(isCellEditable [row col] (= col 2))
(getColumnName [col] (nth column-names col))
(getValueAt [row col] (get-in cluelist [row col]))
(setValueAt [s row col]
(let [word (get-in cluelist [row 1])]
(add-clue word s) ; editing a cell updates the main clue data
(def cluelist (assoc-in cluelist [row 2] s))
(. this fireTableCellUpdated row col))))
table (JTable. table-model)
]
; some pure display stuff elided
(def model table-model)
)
(defn update-cluelist []
(def cluelist (active-cluelist))
(.fireTableDataChanged model))
Someone in another discussion noted that it is a major code smell for (update-cluelist) to be manually calling fireTableDataChanged, because nothing outside the TableModel class should ever be calling that method. However, I feel this is an unavoidable consequence of the table being dynamically generated from an external source. The docs aren't too helpful - they state that
Your custom class simply needs to invoke one the following
AbstractTableModel methods each time table data is changed by an
external source.
which implicitly assumes that the CustomTableModel class is the authoritative source of the data.
Also there is a bit of a clojure/java impedance mismatch here - in java I would have had cluelist and update-cluelist be a private member and method of my TableModel, whereas in clojure cluelist and the table model are dynamically scoped vars that update-cluelist has access to.
My main problem is that there is not a lot of clojure/swing code around that I can look to for best practices. Does anyone have any advice as to the best way to do this?
Suggestion: use an atom for cluelist. Constantly redefining cluelist is not the right way to represent mutable data. Honestly, I would expect it to throw an exception the second time you define cluelist.
If you use an atom for cluelist, you can call the fireTableDataChanged method from a watcher instead of calling it manually. This would mean that anytime (and anywhere) you change the atom, fireTableDataChanged will be called automatically, without an explicit call.
The issue with def is that calling def multiple times doesn't work well in a multi-threaded environment and Clojure tries to make everything default to fairly threadsafe. As I understand it, the "proper" way to use a var is to leave its root binding alone (ie, don't call def again) and use binding if you need to locally change it. def may work the way you are using it, but the language is set up to support atoms, refs, or agents in this sort of situation and these will probably work better most of the time (ie you get watchers). Also, you don't need to worry at all about threads if you add them later.