This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-08-08
Channels
- # 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)
- # 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)
- # xtdb (2)
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
Massive red flags. Whoever wrote that hasn't the faintest clue of Clojure.
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.
(to be honest, I consider tutorialspoint to be a pile of junk)
I agree with @hiredman -- it's more confusing than helpful @gagan.chohan
It's a terrible tutorial (now that I've actually read it!).
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.
^ That's not the official docs BTW
Official docs for loop https://clojure.org/guides/learn/flow#_recursion (as a guide).
Tutorialspoint is often just plain wrong. I strongly advise ignoring it.
http://clojuredocs.org is not official either @gagan.chohan -- it's a community site, with community-submitted examples.
I always thought it to be official, since when you Google, it comes at top, and has org at end
http://clojure.org <-- official; http://clojuredocs.org <-- community
also http://clojure-doc.org <-- community
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
What programming language(s) are you familiar with already?
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
(Clojure's for
loop is like for-comprehensions in Python, I think?)
(! 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 if
or 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 loop
expression.
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.
Not sure if that is clear, but I'll take a breath there.
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 loop
/`recur` and for
trip beginners up quite a bit depending on their background / other languages.
Since you know Python, Clojure's for
is probably more familiar already.
I have one question , might not be related to clojure, so if I specify +10:00 as timezone in clojure, which means melbourne is +10 hours ahead of UTC, does it affect calculations, when day light saving hours are used or not
It depends on how you set it but if you just use an offset, than I guess the DST is not accounted. But you should probably only use ZoneId
(when speaking in terms of java.time)
I had to write a function for printing an Instant
formatted for local time just the other day:
(defn format-ts
[timestamp]
(let [zone (ZoneId/systemDefault)
zone-rules ^ZoneRules (.getRules zone)
zone-offset (.getOffset zone-rules timestamp)
local-time (LocalDateTime/ofInstant timestamp zone-offset)
fmtr (jt/formatter "YYYY-MM-dd HH:mm:ss")]
(jt/format fmtr local-time)))
so 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.
Hi guys. Does clojure compile the code to jvm bytecode or java sourcecode?
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 defrecord
deftype
?
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
Not sure what your question is about strict types
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.
well certainly vectors and maps are used far more commonly than lists
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.
I know that php and js are allocating memory by blocks, for future.
As I understand vector is an analog to array.
it has an indexed api, like arrays
the implementation is actually a tree (of arrays)
but I'm not sure why you should care
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.
you won't get npes when using maps
even untypized maps?
maps just return nil if the key is not present
Thank you a lot.
and you can supply a value to return instead if needed
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 \t
and \n
. Looking a bit messy. Wondering if the community has a standard procedure for outputs like this.
For example
(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
so (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]))))
something like
(defn p [form]
(if (coll? form)
(doseq [thing (seq form)]
(p thing))
(print form)))
could be usefuluser=> (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
yogthose/Selmer
is always my go-to library for templating.
@seancorfield Cool. I will check it out.