This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
- # announcements (43)
- # architecture (4)
- # beginners (115)
- # calva (6)
- # cider (4)
- # circleci (4)
- # clara (3)
- # clj-kondo (6)
- # cljs-dev (10)
- # cljsrn (1)
- # clojars (1)
- # clojure (108)
- # clojure-boston (1)
- # clojure-dev (4)
- # clojure-europe (5)
- # clojure-italy (6)
- # clojure-nl (13)
- # clojure-uk (17)
- # clojurescript (47)
- # core-async (2)
- # crux (2)
- # cursive (13)
- # data-science (1)
- # datavis (15)
- # datomic (12)
- # graphql (5)
- # juxt (10)
- # kaocha (20)
- # lumo (1)
- # off-topic (27)
- # pedestal (4)
- # reitit (2)
- # shadow-cljs (115)
- # spacemacs (4)
- # sql (74)
- # tools-deps (79)
- # vim (15)
I was looking at https://www.tutorialspoint.com/clojure/clojure_loop_statement , the loop thing, I can't understand how it is different from a for loop in other languages
It seems they just googled "how to do x" where x is the things they typically do in languages they are familiar with.
Loops in other languages are almost always statements and have no value. Loops in Clojure return a value from the whole loop evaluation.
so a function like
(defn f [a] (f a)) as a loop would be
(defn f [a] (loop [b a] (recur b)))
Several of the examples here https://clojuredocs.org/clojure.core/loop are much better.
Official docs for loop https://clojure.org/guides/learn/flow#_recursion (as a guide).
I always thought it to be official, since when you Google, it comes at top, and has org at end
It doesn't make them "bad" necessarily, but if there are any incorrect examples on them, it means that they unfortunately might remain that way for some time, until someone confident enough that they are correct notices and updates them.
Recur is kind of tricky to explain without backing up a long way into recursion and iteration and their expression in functional languages and how they are usually optimized because it exists in dialog with that history
You are certainly welcome to ask here, of course, about any such examples, but in general, Google and other search engine results are not the decider of what is 'official' documentation.
It's kinda confusing because https://clojure.org/api/cheatsheet, the cheatsheet on official site also points to clojuredocs
The official docs/site (http://clojure.org) points to a lot of community resources.
So you may get this in slightly different variants from multiple people here, if we're not careful 🙂 I'll let hiredman go for it 🙂
Often in functional langues iteration (for loops or while loops in C) are expressed as recursive function calls and the compiler recognizes those recursive calls as being loops and compiles them as such. Clojure doesn't do that, and instead provides the less general combination of loop/recur which in usage follow the same pattern as an iterative process encoded as recursive function calls
(! 604)-> python Python 2.7.10 (default, Feb 7 2017, 00:08:15) [GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.34)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> [2 * x for x in [1, 2, 3, 4]] [2, 4, 6, 8] >>> ^D Wed Aug 07 19:18:23 (sean)-(jobs:0)-(/Developer/workspace/wsmain/build) (! 605)-> clj Clojure 1.10.1 user=> (for [x [1, 2, 3, 4]] (* 2 x)) (2 4 6 8) user=>
I actually have a hard time not jumping in, after all. Maybe one way to think of
loop in Clojure is that while it is possible to write loops similar to how they are written in imperative languages, it is definitely not typical "idiomatic" Clojure code. A purely functional
loop expression does not modify any values that are visible when you enter the loop, and technically it doesn't modify the 'loop variables' either. The first time you start the
loop, the symbols given in square brackets are 'bound' (similar to assigned, but only once) to the initial values shown.
Leave out the possibility of nested
loop expressions for simplicity for the moment.
The loop body is evaluated, say having some conditional expressions like
cond, but no assignment statements like you would find in imperative languages.
Either that branching ends with evaluating an expression that is not a
recur expression, and that value becomes the return value of the entire
Or it ends with evaluating a
recur expression. That is similar to a recursive call to the beginning of the loop expression, with new initial values for all loop 'variables' (except they are not variables). So those loop variables are kinda sorta "assigned a value only once at the beginning of each loop iteration", not at arbitrary points in the middle.
To illustrate Andy's description
user=> (loop [acc 0 n 10] (if (pos? n) (recur (+ acc n) (dec n)) acc)) 55 user=>
So that is maybe a 'negative' way to explain it, by the restrictions imposed on you -- you get to 'assign' (really 'bind') a value to the loop 'variables' (more technically 'symbols') at most one time per iteration through the loop, not any number of times you want like you could in imperative programming languages. Also the loop symbols are purely local to the loop -- they are out of scope when the loop returns (again, unlike in most imperative languages).
What do you get in return for those restrictions? You get something easier to reason about. Frankly, it can be a little mind-twisting at first when trying to write such loops, and there are plenty of other Clojure functions that handle the common cases of what you want to do looping for, e.g. map, filter, remove, reduce, and those are often clearer than a loop, when they do what you need.
Yeah, probably Sean had a better idea to start with a small useful example, rather than throwing all the general rules at you as I did 🙂
I think I understand it now, played around with Sean's example, now I can understand more complex examples too
Excellent! I think
for trip beginners up quite a bit depending on their background / other languages.
recur has to come in the "tail position" right? So I often find myself changing the logic in my head and function to put the
recur in the
else branch of the
if statement. But in seancorfield's loop/recur example above, it is in the
then position which I guess makes sense because only one branch is evaluated so whichever branch it is is considered the tail position?
One way to deal with this is to take whatever is causing the other branch, and make it another argument to your fn.
“tail position” means that the recur has to come last in whatever statement it’s in, so it’s not correct to say that the “then” or the “else” is in tail position, both those statements can contain recur as long as it is the last form. for instance, this is perfectly legal:
(loop [x 0] (if (< x 10) (recur (+ x 2) (recur (+ x 1)))
periodic reminder: if there are beginners here who would like to work on open source issues, here are some ideas: https://clojureverse.org/c/questions-help/starter-issues
a much bigger list (although not sure if up-to-date) is here: http://open-source.braveclojure.com/
hi everyone. I am newbie in clojure. I want to know how to halt future in clojure from executing functions before finishing future's processing?
@U06BE1L6T Dont want to cancel future, just to halt future from executing some dependancy functions before future's processing.
There's nothing like that, imho. You should do this explicitly inside your future if it has some dependencies. Relying on thread scheduling is extremely fragile
How to do multi threading using go block of core.async ? can anyone give some examples? i have gone through docs but can't understand properly yet.
I just read that someone was upset that > a macro can only evaluate to a single form I'm confused, first can some point to the definition of form so I can be 100% I get it? Secondly, assuming a form can be a collection, this wouldn't seem to be a limitation.
Loosely speaking it’s a unit of code wrapped in parentheses, so
(def foo 1) is a form and
(let [a 1] (println a)) is a form inside a form (but the
[a 1] bit is not itself a form).
What about strict types? I got null pointer exception few times.
How often do you use
The bytecode compiled from Clojure is not directly representable as Java source code
When doing interop, Clojure makes no effort to protect you from NPEs and that's the main place you'll see them
deftype is used rarely (it's really for creating new data structures). defrecord is used sometimes, depends on need, often maps suffice
Currently, I build my small program only with lists. And now, I start suspecting that I may do something wrong. And there is a better way.
but I wouldn't recommend making "types" with defrecord unless you have a good reason to do so
I a little bit affraid of vectors. Because list is a ... list. But I do not know, how does clojure allocate a new memory for it.
About NPE. I want the compiler to check, that a value with index :a (for example) will be in that map. That`s why I am thinking about records.
maps and records implement the exact same interfaces and in general (there are a couple exceptions, but they are not something you will normally run into) will give you the same result, so consumers don't care
Is there an implementation of a macro similar to a Ecma Script “Template literal”? I have some
(println) forms in a small project that are suffering from a rash of
\n. Looking a bit messy. Wondering if the community has a standard procedure for outputs like this.
(println "\tBranch: "(:git.branch body) "\n" "\tCommit ID: "(:git.commit.id body) "\n" "\tCommit ID Short: "(:git.commit.id.abbrev body) "\n")
you could use format, and strings are allowed to span multiple lines and have real newlines in them
(println (format "\tBranch: %s \tCommit ID: %s \tCommit ID SHort: %s " (:git.branch body) (:git.commit.id body) (:git.commit.id.abbrev body)))
it does look awkward that the next line of the string needs to be unindented though
yeah - also note that you could probably do something with string/join for the \n\tab combos
(println (apply format (string/join "\n\t" ["\tBranch: %s" "Commit ID: %s" "Commit ID Short: %s"\n"]) (map body [:git.branch :git.commit.id :git.commit.id.abbrev]))))
could be useful
(defn p [form] (if (coll? form) (doseq [thing (seq form)] (p thing)) (print form)))
user=> (p [\tab "Branch: " (gensym) \tab "Commit ID: " (gensym) \tab "Commit ID Short: " (gensym) "\n"]) Branch: G__145 Commit ID: G__146 Commit ID Short: G__147 nil user=>
if you want templating i'd look into a real string template lib there's a few good ones