This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-05-12
Channels
- # announcements (2)
- # aws (1)
- # beginners (63)
- # cider (2)
- # clj-kondo (1)
- # cljdoc (15)
- # clojure (114)
- # clojure-nl (1)
- # clojure-spec (15)
- # clojure-uk (10)
- # clojurescript (5)
- # clojutre (1)
- # community-development (6)
- # cursive (18)
- # data-science (1)
- # datascript (16)
- # datomic (2)
- # emacs (2)
- # events (3)
- # figwheel-main (2)
- # graphql (3)
- # jobs (2)
- # off-topic (23)
- # reitit (3)
- # shadow-cljs (27)
- # spacemacs (5)
- # sql (27)
- # unrepl (1)
Hi, I'm trying out clojure and it's completely different to what I'm used to. Is this the correct way to write clojure? What I'm trying to do is to take the first 2 element of the queue, combine them and append them to the end. The way I have to do double pop and pop then peek felt especially awkward. Usually I would just save the queue to a var and mutate it (but we can't mutate stuff in clojure?). Thank you.
(defn tournamentTree [queue]
(if (= (count queue) 1)
queue
(recur
(conj
(pop (pop queue))
{:firstSlot (peek queue)
:secondSlot (peek (pop queue))}))))
(defn -main
[]
(println
(seq
(tournamentTree (conj clojure.lang.PersistentQueue/EMPTY 1 2 3 4)))))
@tiennguyenkhac1702 Just to clarify, given [1 2 3 4]
, you're trying to get [3 4 1 2]
?
({:firstSlot {:firstSlot 1, :secondSlot 2}, :secondSlot {:firstSlot 3, :secondSlot 4}})
this is my final out put
Which is what I'm trying to get
Just wondering if I'm using clojure the right way :))
Take a look at destructuring for how to break apart sequences. You probably don't really need a queue here.
Although it feels like you just want to repeatedly partition
into pairs, recursively until you have just one element left.
I'd have to give this a bit of thought...
Yeah, what I'm trying to do is to build a tournament bracket
But all of these seem rather excessive or odd? (pop (pop queue))
(peek queue)
(peek (pop queue))
How about something like this
user=> (defn tree [l] (if (= 1 (count l)) l (recur (map #(zipmap [:first :second] %) (partition 2 l)))))
#'user/tree
user=> (tree [1 2 3 4 5 6 7 8])
({:first {:first {:first 1, :second 2}, :second {:first 3, :second 4}}, :second {:first {:first 5, :second 6}, :second {:first 7, :second 8}}})
user=>
Destructuring would help you (let [[a b & more] queue] ...)
-- a
is the first element, b
is the second, and more
is the rest of the queue
Not sure what your code would do with, say, six elements. My suggestion ignores the last two elements, but you could use partition-all
to solve that.
user=> (defn tree [l] (if (= 1 (count l)) l (recur (map #(zipmap [:first :second] %) (partition-all 2 l)))))
#'user/tree
user=> (tree [1 2 3 4 5 6])
({:first {:first {:first 1, :second 2}, :second {:first 3, :second 4}}, :second {:first {:first 5, :second 6}}})
user=>
Seem a lot more sensible, I'll have a read into partition and zipmap. Thanks
And #(zipmap [:first :second] %)
is some sort of shorthand for anonymous func? I clearly have a lot to learn š
Just understand ur code and wow, that recursive zip map + partition seem so expessive, I think I'm super hooked on clojure now, thanks
@tiennguyenkhac1702 correct
(macroexpand '#(zipmap [:first :second] %))
=> (fn* [x#] (zipmap [:first :second] x#))
I donāt think you need macro expand there. If you quote the form you can see it as well. ā#(inc %)
@tiennguyenkhac1702 Clojure is extremely powerful so if you think your solution is complex or repetitive, there's probably some useful core functions that will make it simpler and cleaner -- but it can take a long time to learn enough of them that you internalize the "Clojure way".
The main thing is to try to think "holistically" about collections, rather than individually about elements. And that just takes time and practice. practice, practice.
Thanks @seancorfield, will pretty much have to āun-programā how I used to think about programming now (top-down instead of bottom-up)
Yeah, FP in general -- and Clojure in particular -- is a whole new way of thinking š
Iām trying to learn some concurrency techniques through building an integer factorization function. Iām totally new to core.async
and quite confused.
Here is what Iām trying to do: My input is some number n
, and I need to have a loop
where, on every iteration, some prime factor pf
of n
is found, then n
is divided by the factor pf
and the loop repeats until n
is 1. This is easy when one factoring algorithm is involved.
Now, I have 2 or 3 (depending on the size of n
) competing algorithms that can try to find a factor of n
. The thing is, they wonāt all finish at the same time, they might fail (and return nil
), and if they do return a factor, that factor may not necessarily be prime.
This is as far as I got. Iām sure itās not at all how you are supposed to write concurrent code. I havenāt implemented the prime check (since sliding-buffer
s canāt take xf
s). One other thing that I need to do, but donāt know how, is to flush the channels on each loop. Because if one channel keeps a value taken from the n
of a previous iteration, alts!!
will take it, even though itās no longer useful.
Can someone describe the basic outline of how to accomplish this?
@tabidots You might need to ask in #core-async but if you think you need to "flush the channels" then I'd say your approach is fundamentally wrong. All values pushed to all channels should be consumed, in general.
Hmm. So there is no way to āraceā a few functions on each iteration and take the earliest new result?
Like a parallel or
that short-circuits, I guess is another way to describe what I want
Yeah, but then all the source channels need to be created each time around the loop.
And you're just pushing a single value onto each channel, and then taking (essentially) a random one of those three values, right? And throwing the other two away.
yes, random in the sense that I donāt know with certainty which one will finish first.
If you move the let
(that creates the channels) inside the loop
, I think that will solve your originally basic problem -- since it will create new channels for each iteration -- but it "looks" wrong to me, based on the async code I've seen, having just a single set of channel operations each time (rather than having longer-lived channels that a sequence of values flow through).
I was thinking that (on both counts)ā¦ Is it wasteful to create new channels every iteration just to hold a single value, and then close them? (Or ignore them, I guess?)
That's why it feels like a "code smell" to me...
I was trying to take the idea described here: https://pypi.org/project/primefac/
primefac uses by default five threads to take advantage of the multiple cores typically available on modern machines. Each of these threads uses a different algorithm to factor the number
Although Iām taking a look at the source now, as well as a similar Python script I culled from GitHub, and neither of them do the āparallel short-circuiting or
ā that I had imagined
Each factorization can return onto a channel and you watch from your main loop for the first to return
Iāve currently got alts!!
in there, and it worksābut because the channels donāt flush their values on every iteration of the loop, sometimes alts!!
takes a no-longer-useful value from a channel. (Because the first to return might be a leftover value from a previous iteration)
I see from the Python scripts Iām looking at that they hold off on the concurrency until it is really warranted, and then (do the equivalent of) a/merge
-ing the values from 5 channels rather than racing the channels against each other. So I guess thatās the way to do it
Looks like there's discussion about getting clojurescript on code sandbox: https://github.com/codesandbox/codesandbox-client/issues/704
Someone wants to know about "Github Starter project for Reagent / ClojureScript?" What's the best thing to recommend, figwheel or figwheel main (I didn't know there was a new figwheel) or shadowcljs?
If they are coming from JS and would like to use things from npm, shadow-cljs is much more streamlined.
Damn, I love Clojure. On Friday I was struggling how to compose all different parts in my new Clojure learning project and now on Sunday it seems that suddenly all pieces are going to the right places.
I learned to use a Clojure scratch file and it is so much more efficient to write Clojure expressions in the scratch file and send them to repl with a simple hot key instead of writing expressions in the repl - I should have watched this great presentation earlier: https://vimeo.com/223309989 (see 35:00).
And using Mount I suddenly realized that I actually don't need to start my app with two different configurations in two different REPLs (single-node or aws) - I can switch dynamically in the same REPL from one configuration to another.
And I love all my IntelliJ IDEA / Cursive hot keys (e.g. delete everything from the cursor till end of S-expression, put S-expression after cursor to kill-ring...). Coding Clojure is so fast when you use good hotkeys and Paredit.
Studying and practice really makes a difference. I'm re-implementing the same server I did using Clojure one year ago, and now many thinks are much clearer. I'm really excited with this new implementation and with my new Clojure skills - I feel like a small boy who got bunch of techno legos for a Christmas present and now figuring out what kind of wonderful things to build with them. š And Clojure REPL is just so wonderful development tool - nothing I have ever seen with any other language I have used.
The wonders of programming ^^!
I agree @kari.marttila, Clojure is really enjoyable š
Yep. And now when I know how to use REPL more effectively I feel like my Clojure development suddenly got boosted some 2x š .
Clojure is so beautiful and productive language. We really should do more to let every developer know and understand what programming can really be at its best. I'm pretty sure that 50% of programmers would turn to Clojure if they only could feel this productivity and what a joy it is to have a real REPL.
I gave a presentation based on my "Five Languages - Five Stories" blog article (https://medium.com/@kari.marttila/five-languages-five-stories-1afd7b0b583f) in my corporation. There were quite a lot of developers gathered. I tried to explain what it is to have a real REPL. One developer said: "I use Scala, there is also a REPL in Scala." I answered that I haven't used a Scala REPL but if it is anything like a Java shell you can't talk about those REPLs in the same day.
The Scala repl is more of a torture device than a useful part of the workflow, in my experience
@kari.marttila Yeah, once you've set up and then internalized a really good REPL workflow, it's hard to imagine working any other way š