I am quite new to Clojurescript and LISPy languages, so please excuse my imperative way of thinking.
I'm using Raphael.js to draw some things. It lets you define a set, push things into the set (say, a circle, a rectangle, and a path), and then perform an operation that acts upon all items (example: a rotation that applies to all).
So we can have (where paper is basically the svg element):
(-> (.set paper)
(.push (.ellipse paper 10 10 10 10))
(.push (.circle paper 10 10 10 10))
(.transform (format "r%.2f" 180)))
Which will create a set and use multiple calls to push which returns the set each time, eventually calling transform. Now what if I want to create a list of say circle objects at runtime and add them to the set? What i'd ideally like to be able to do is to replace say line 3 of the above code block with something like (very roughly - i'm completely unsure about how to deal with the .push)
(.push (map (fn [i] (.ellipse paper 10 (* i 10) 10 10)) (range 5)))
in order to create 5 circles coming down the y axis. What I can't quite figure out with my limited grasp of Clojure is how to do such a thing in a fairly idomatic way without resorting to a doseq somewhere else. I don't want side effects. I'd like to somehow create a list of pushes and then have them all compose themselves into my block in-place. Is that possible? There may be a huge flaw in my thinking somewhere and I'd be really very grateful to anyone who can point that out.
Many thanks.
Avoiding side effects is a little tricky since push apparently mutates the set. One way to avoid doseq is to use reduce. For example:
(def shapes [ (.circle paper 10 10 10 10) (.ellipse paper 10 10 10 10) ] )
(defn push-all [set shapes]
(reduce #(.push %1 %2) set shapes))
(-> (.set paper)
(push-all shapes)
(.transform (format "r%.2f" 180)))
Related
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.
Clojure newbie here, I was going through the excellent "Clojure from the ground up" posts, and tried out the last exercise in this post.
When I replace alter with commute, the sum is inaccurate, but I don't understand why.
(def work (ref (apply list (range 1e5))))
(def sum (ref 0))
(defn trans-alter [work sum]
(dosync
(if-let [n (first #work)]
(do
(alter work rest)
(alter sum + n)
(count #work))
0)))
(defn trans-commute [work sum]
(dosync
(if-let [n (first #work)]
(do
(commute work rest)
(commute sum + n)
(count #work))
0)))
(I've skipped the code that sets up the futures and calls them etc)
With trans-alter here I got 4999950000 for the sum (which is the correct expected value), while with trans-commute I got a different value each time, but higher than expected (e.g. 4999998211).
What am I missing here? Thanks in advance!
Commute and alter essentially do the same thing, though commute is a little more lenient on the guarantee of correctness.
Alter instructs the STM to always ensure that this code ran all the way through without any of the refs it uses changing out from under it.
Commute is an instruction to help the STM decide when it needs to abort a transaction because the underlying data changed out from under it.
If everything in a transaction is commutative, then it's ok to let that transaction finish even if some data changed. In your case two transactions could both:
grab the first number
remove the same number from work
add the same number to result
then use commute to instruct the STM that this is OK, and it should just go ahead and commit the transaction anyway...
get the wrong answer.
So in short,the work you are asking to preform is not actually a commutative operation. Specifically removing an item from a list is not commutative. If you change any of the commutes to an alter, then step 4 would have kicked one of them out and only allowed one of them to finish. The one that got kicked out would be re-run on the fresh data and eventually would have arrived at a correct result.
I'm building a ClojureScript app and I'm having trouble with using reagent to fill a table with data. The two issues I'm having are TONS of warnings of the form
Every element in a seq should have a unique :key
And also, as soon as I call the function that does the rendering, it renders correctly, then my entire page freezes and reloading the page is the only way to fix it. These are my two functions:
(defn foo
[]
[:table
(for [i (range 10)]
[:tr (for [j (range 3)]
[:td (str "Row " i ", Col " j)])])])
And when I call the following, I get the warnings and the page freezes, though it does render correctly:
(reagent/render [foo] (dom/getElement "results"))
Am I approaching the process of filling in data the wrong way? Is there an easier way?
The warning you are getting is due to reagent requiring a unique key value for dynamic elements created along these lines. There are a couple of ways you can fix this. The other thing you need to watch out for is possible issues with using for because it generates lazy sequences. While this is working for you in this context, it can create subtle issues with re-rendering.
My advice would be to create a function to render the td element and prefix the rendering with
^{:key (str i j)} [:td (str "Row " i ", Col " j)]
The (str i j) will create a unique key for each td element. The other thing I find useful is to use into i.e.
(into [:tr]
(for [j (range 3)]
^{:key (str i j)} [:td ....])))
I've been developing my own app using reagent. It isn't great code and it still needs a lot of re-factoring, but I have done tables like this as well as paginated tables and a few other reagent components, such as tabs, sidebar menus etc. It can be found at my github arcis project It should give you some ideas if nothing else
There is also some good documentation regarding reagent and how it does rendering and some of the subtle 'gotchas' at re-frame wiki
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.
Clojure and enlive are great. In trying to fathom the power of Enlive I'm attempting to apply two transformations to an html page.
The HTML page has 2 areas (divs) that I want to transform. The first div in question gets cloned ~16 times. The second div in question gets cloned 5 times. The original divs (from the html file) should be overwritten or just not appear at all.
Enlive has the idiomatic approach
(apply str (enlive-html/emit* ze-contant-transferm))
this works beautifully well for one transform.
however, I would like to apply two transforms to the page, so I tried something like:
(str
(apply str (enlive-html/emit* ze-first-wan))
(apply str (enlive-html/emit* ze-secand-wan)))
the transformations, done alone, do exactly what I wish: they eat up the original HTML and display the clones that I use for populating with infos.
However, done together in this way, the original html-page divs are preserved, so I end up having the original html file divs along with my clones, and that behavior is no bueno.
Please help.
Thanks-a-much-a.
Enlive-html provides the do-> function for this purpose.
(defn do->
"Chains (composes) several transformations. Applies functions from left to right."
[& fns]
#(reduce (fn [nodes f] (flatmap f nodes)) (as-nodes %) fns))
Which you can use something like this:
(apply str (enlive-html/emit* (enlive-html/do-> ze-first-wan ze-second-wan)))