Im sure I have read somwhere how it is possible to use the reconciler to test query expressions in Om Next directly but im not able to find the source again or figure out if this is possible based on the Om documentation. Is this possible to do so and if it is, how?
What I have right now to test is using the parser but I was hoping for a better way using the reconciler:
(parser {:state (atom state)} (om/get-query MyQuery))
This is how I currently find the value of top level keywords:
(defn query [kw]
(let [res (my-parser {:state my-reconciler} `[[~kw _]])]
(when (not-empty res) (apply val res))))
So in your case you could try:
(my-parser {:state my-reconciler} (om/get-query MyQuery))
It looks like the value for :state can either be a state you give it as in your example, or the reconciler itself as in my example.
It depends on what you mean by "test query expressions in Om Next directly"? The code you wrote above is the only way to check how the parser will interpret the query you give it.
If you're wanting to see how the app state will be normalized and denormalized using the queries you provide, maybe the documentation for idents and om/tree->db is closer to what you're looking for.
Related
I'm learning Clojure by following the Hackerrank 30 days of code, and lost some hours due to a behavior I neither understand nor found any documentation or explanation about:
(read) returns a symbol:
user=> (def key-read (read))
sam
#'user/key-read
user=> (type key-read)
clojure.lang.Symbol
(read-line) returns a string
user=> (def key-line (read-line))
sam
#'user/key-line
user=> (type key-line)
java.lang.String
As a result, parsing a line with (read) (read) to get map keys and values results in the keys to be symbols, than will never be matched by a further (read-line).
Why is this so? And also, where can I find the return value? (this is not documented in (doc read)).
TL;DR
clojure.core/read is used to read "code" by Clojure itself
clojure.edn/read is used to read "data" (EDN)
read-line is used to read text lines as string; it's your problem to
decipher them
What can read do for you
read does not only read symbols, but anything, that Clojure uses to
represent code. If you give it a symbol to parse, it will give you
symbol back:
(type (read))
test
clojure.lang.Symbol
But also other things
(type (read))
5
java.lang.Long
(type (read))
{:a 42}
clojure.lang.PersistentArrayMap
(type (read))
"hello"
java.lang.String
So you can get back a string with read too, if you feed it a string.
real-world use of read
Usually read is used by Clojure itself and that's it. Reading
EDN is usually done using clojure.edn/read, which does not allow code
execution and therefor is no security risk if handling EDN from
untrusted sources.
docs
For good measure, here are the docs:
(doc read)
-------------------------
clojure.core/read
([] [stream] [stream eof-error? eof-value] [stream eof-error? eof-value recursive?] [opts stream])
Reads the next object from stream, which must be an instance of
java.io.PushbackReader or some derivee. stream defaults to the
current value of *in*.
Opts is a persistent map with valid keys:
:read-cond - :allow to process reader conditionals, or
:preserve to keep all branches
:features - persistent set of feature keywords for reader conditionals
:eof - on eof, return value unless :eofthrow, then throw.
if not specified, will throw
Note that read can execute code (controlled by *read-eval*),
and as such should be used only with trusted sources.
For data structure interop use clojure.edn/read
(doc read-line)
-------------------------
clojure.core/read-line
([])
Reads the next line from stream that is the current value of *in* .
You can find the Clojure API documentation at https://clojure.github.io/clojure/clojure.core-api.html. Both read and read-line are there.
Your specific goal isn't quite clear, but in general, application software prefers read-line and parses the results in whatever way makes sense... perhaps with re-matches for regular expressions. Clojure itself reads program code with read.
The other 2 answers are good. I didn't even know that clojure.core/read existed!
I only wanted to add in a list of my favorite documentation sources.
Please review & study the Clojure CheatSheet, which links to examples on clojuredocs.org.
Unfortunately, the API docs at clojure.org are not as descriptive and it is harder to find things unless you already know the name and location.
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.
for an assignment I need to create a map from a text file in clojure, which I am new to. I'm specifically using a hash-map...but it's possible I should be using another type of map. I'm hoping someone here can answer that for me. I did try changing my hash-map to sorted-map but it gave me the same problem.
The first character in every line in the file is the key and the whole line is the value. The key is a number from 0-9999. There are 10,000 lines and each number after the first number in a line is a random number between 0 and 9999.
I've created the hashmap successfully I think. At least, its not giving me an error when I just run that code. However when I try to iterate through it, printing every value for keys 0-9999 it gives me a stack overflow error right at the middle of line 2764(in the text file). I'm hoping someone can tell me why it's doing this and a better way to do it?
Here's my code:
(ns clojure-project-441.core
(:gen-class))
(defn -main
[& args]
(def pages(def hash-map (file)))
(iter 0)
)
(-main)
(defn file []
(with-open [rdr (clojure.java.io/reader "pages.txt")]
(reduce conj [] (line-seq rdr))))
(defn iter [n]
(doseq [keyval (pages n)] (print keyval))
(if (< n 10000)
(iter (inc n))
)
)
here's a screenshot of my output
If it's relevant at all I'm using repl.it as my IDE.
Here are some screenshots of the text file, for clarity.
beginning of text file
where the error is being thrown
Thanks.
I think the specific problem that causes the exception to be thrown is caused because iter calls itself recursively too many times before hitting the 10,000 line limit.
There some issues in your code that are very common to all people learning Clojure; I'll try to explain:
def is used to define top-level names. They correspond with the concept of constants in the global scope on other programming languages. Think of using def in the same way you would use defn to define functions. In your code, you probably want to use let to give names to intermediate results, like:
(let [uno 1
dos 2]
(+ uno dos)) ;; returns 3
You are using the name hash-map to bind it to some result, but that will get in the way if you want to use the function hash-map that is used to create maps. Try renaming it to my-map or similar.
To call a function recursively without blowing the stack you'll need to use recur for reasons that are a bit long to explain. See the factorial example here: https://clojuredocs.org/clojure.core/recur
My advice would be to think of this assignment as a pipeline composed of the following small functions:
A function that reads the lines from the file (you already have this)
A function that, given a line, returns a pair: the first element of the pair is the first number of the line, the second element is the whole line (the input parameter) OR
A function that reads the first number of the line
To build the map, you have a few options; two off the top of my mind:
Use a loop construct and, for each line, "update" the hash-map to include a new key-value pair (the key is the first number, the value is the whole line), then return the whole hash-map you've built
Use a reduce operation: you create a collection of key-value pairs, then tell reduce to merge, one step at a time, into the original hash-map. The result is the hash-map you want
I think the key is to get familiar with the functions that you can use and build small functions that you can test in isolation and try to group them conveniently to solve your problem. Try to get familiar with functions like hash-map, assoc, let, loop and recur. There's a great documentation site at https://clojuredocs.org/ that also includes examples that will help you understand each function.
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.
I have 2 maps:
(def look {"directions" :look
"look" :look
"examine room" :look
})
(def quit {"exit game" :quit
"quit game" :quit
"exit" :quit
"quit" :quit
})
which are merged into one map by:
(defn actions [] (merge look quit))
and then I try to associate its result (which is a hash-map) into value of another map:
(assoc {} :1 actions)
but instead of expected result which should be:
{1: {"directions" :look, "look" :look ...
I receive
{:1 #object[fun_pro.core$actions 0x20a8027b "fun_pro.core$actions#20a8027b"]}
which is, as I understand reference to the action object.
What should I do to receive expected result? I tried also use of unquote-splicing but I'm not advanced enough to use macros yet and couldn't make it works.
EDIT1:
OK, It seem I found the solution. Instead of using (defn actions...) I should use (def actions...).
EDIT2:
To clarify why I use such a structure.
As I said in comment below, I will use this maps to compare it with the answer provided by user to find which command to use. For example if user type "show me directions", it will trigger function to display directions based on keyword "directions". The same result will be if user will ask "I look around the room" or "I examine room to find road", based on keywords "look" and "examine room".
It will be done by first splitting user input into set of strings and find if there is common word with keys from my map (turned into set). So input "show me directions" will be processed into set #{"show" "me" "directions"}. Then I will use clojure.set/intersection to find if there is common element with set of map keywords and trigger function accordingly to result (I have already coded algorithm for that).
Of course I'm open for any suggestions if there is better solution for it.
OK, It seem I found the solution on my own. Instead of using (defn actions...) I should use (def actions...).
This results of desired output.