This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-12-12
Channels
- # adventofcode (67)
- # announcements (8)
- # babashka (46)
- # beginners (154)
- # calva (5)
- # cider (9)
- # clara (5)
- # clj-kondo (34)
- # cljdoc (31)
- # cljsrn (4)
- # clojure (146)
- # clojure-europe (5)
- # clojure-italy (3)
- # clojure-losangeles (2)
- # clojure-nl (149)
- # clojure-spec (22)
- # clojure-uk (73)
- # clojured (6)
- # clojurescript (95)
- # clojureverse-ops (3)
- # cryogen (7)
- # cursive (12)
- # data-science (1)
- # datomic (9)
- # docker (1)
- # emacs (1)
- # figwheel-main (1)
- # hyperfiddle (1)
- # jobs (3)
- # malli (29)
- # nrepl (2)
- # off-topic (61)
- # pathom (6)
- # pedestal (1)
- # planck (1)
- # reitit (19)
- # shadow-cljs (52)
- # spacemacs (5)
- # tools-deps (24)
- # vim (30)
- # yada (6)
say i have a macro that iterates all words in list and prints them out.. in the snippet below, with the quoted words
variable defined outside it works (it prints "hello" and "world)
(def words '[hello world])
(defmacro print-words
[]
`(do
~@(for [w words]
(println w))))
but if I change the function such that I pass in that same words as an argument, i.e. (print-words
[hello world])` then it doesn't work (it prints "quote" and "[hello world]")i'm trying to learn why exactly that is, and how to get the second way (passing the quoted list as a function argument) to behave the same
Function calls have their arguments evaluated before the call. Macro invocations do not.
but what exactly does it mean for '[hello world]
to be evaluated before a call, wouldn't it be the same as defining it in an outside scope like I did above?
Do you need a macro for this? If you are trying to learn about how macros work as an exercise, no problem, but if you can do what you need with a function, that is recommended.
The reader reads '[hello world]
and returns the data structure that is this list: (quote [hello world])
If you then evaluate that, all expressions of the form (quote x)
evaluate to the whatever the value of the expression x
is.
If you use that as the argument to a macro, the macro code runs without first evaluating that.
If you use that as the argument to a function, it is evaluated to the value [hello world]
and then the function body executes given that vector value as a parameter.
regarding third comment, you mean it is evaluated to (quote [hello world])
, right? cause that examples why if i iterate over it prints "quote" and "[hello world"
The reader reads '[hello world]
and returns (quote [hello world])
. Evaluating that does not result in (quote [hello world])
You can try it at a REPL and see.
user=> (read-string "'[hello world]")
(quote [hello world])
user=> (eval (read-string "'[hello world]"))
[hello world]
ah yea ok, so think I understand now, it's expanded but not evaluated until the macro fires
If you replace "expanded" with "read", then I agree.
got it. it's my first dive into macros so thanks for the help @andy.fingerhut 🙌
And it pays to be careful about the times involved in invoking macros. There is macro expansion time, which is during compile time, but that is all before the code returned by the macro is executed/evaluated.
I am not clear which of those times you might be referring to by "until the macro fires"
was referring to when i actually call function in repl and see result, so yea the latter
It also pays to distinguish "call function" and "invoke macro" when talking about the behavior here. Not sure which function you mean. Technically, in the implementation, a macro is a function, but it is a function that is passed unevaluated parameters of the macro invocation during compile time, executes during compile time, returns a new expression, and the returned expression is fed back into the compiler (perhaps causing more macros to be expanded), all before the resulting code is evaluated.
The exploding head syndrome is common, and is one of the reasons to avoid using macros if you do not need them 🙂
i'm actually trying to contribute to a library that already uses them (to dynamically generate react elements) so using it as a chance to learn
Rich Hickey's talk "Clojure for Java programmers" has an interesting introduction to the read time, compile time, where macros fit in, etc. Not sure if it would be helpful, but thought I would mention it: https://github.com/matthiasn/talk-transcripts/blob/master/Hickey_Rich/ClojureForJavaProgrammers.md
When trying things out and debugging, functions like read-string
, eval
, macroexpand-1
and clojure.walk/macroexpand-all
can be useful.
I'm trying to create a REST api with pedestal and datomic... why do I need a deps.edn and a project.clj ??
aren't both for the same thing? (managing dependencies)
It is possible to create a project that uses deps.edn, and never uses Leiningen, therefore needs no project.clj file.
If you use Leiningen, you need a project.clj file.
so if i want to run the api locally
with lein run
i should mantain both?
You can start a REPL, and/or run the project locally, without using lein. e.g. use clojure
or clj
commands instead.
leinengen does not normally need deps.edn
(though it can use it via a plugin - some people prefer that)
ohhh ok
is there a reason I should use leiningen for my purposes ?
Depends on your purposes 🙂
hahaha you're right
You can most likely do everything you need with clojure
/`clj` and deps.edn
...
why do people use lein?
...but Leiningen is in nearly all the books and tutorials because it's been around the longest. The CLI / deps.edn
is relatively new.
I believe there are ClojureScript-specific tool environments that pretty much require Leiningen today. If you have Java source in your project, and you want to have a tool to build that for you into .class files, then clj
/ clojure
commands alone will not do that for you.
Strictly speaking, you can compile Java with the CLI but it isn't straightforward -- but you don't need other tools 🙂
Sure, if you can write a Clojure program to do what you want, you can use clj
and clojure
commands to run that code for you.
No, I mean you can do it with just the -e
option 🙂
Compile Java source code?
Yup. I posted an example somewhere. -e
and clojure.java.shell/sh
to invoke javac
🙂 🙂 🙂
Sure, you wrote Clojure code to do what you want, as I said 🙂
But not a separate program: just a single clojure
CLI invocation. I think that's important.
When we started with Clojure back in 2010/2011, Leiningen was the only choice. We switched from Leiningen to Boot in 2015 and from Boot to CLI/`deps.edn` about a year ago.
Ohhh nice! Thank you guys!
This slack is amazing... I was having a hard time finding a lot of information until I discovered it
If you're just getting started with Clojure in 2019, I'd suggest trying to use the CLI/`deps.edn` and learn all the ins and outs by reading the docs on http://clojure.org and asking questions here.
Great, thanks!
If you do go down the CLI/`deps.edn` path, take a look at https://github.com/seancorfield/dot-clojure as a way to jumpstart your experience with it.
You need other tools for what's missing which you can hook up to clj, kinda like extending it with additional plugins
Where as lein has a lot of included build like features. Though even with lein, there are some things when you need additional plugins for
But in general lein has one and only one way to do things, and a set of common additions
For better or worse. Its unclear which one would be easiest to pick up, probably depends on what you're doing exactly
I think lein
is "easier" but clj
is "simpler" 🙂
Hi every one I've been a JavaScript programmers for more than 10 years and in my journey to functional programming with JavaScript I was introduced with clojure and I'm really interested The thing is I just can't start coding with clojure, I find myself reading and reading and ... watching talks about clojure I just can't start Any idea what should I do?
Have you tried the Clojure Koans?
That's a nice, gentle hands-on approach to writing little bits of code in narrative.
That's a good one. Try http://4clojure.com
@hojatjafari What books / tutorials have you read through so far? Have you read Brave and True?
That might be great if there was a tutorial that walks you trough implementation meaningful things and teaching new things as you use it in context of what you're building
Hmm, Living Clojure might be worth a try by Carin Meier. If you don't mind actually buying a book.
I'll give it a shot Ty @seancorfield
Hi, I have a number of events (e.g. 4 events) and want to distribute them evenly within a week, how would you approach this problem? I am a JS-Developer and I would use https://github.com/d3/d3-scale for that. Is there sth similar in clj or do I need to write my own logic?
Hey guys, I need to write some predicate functions. What will be the most idiomatic way to write predicate functions? For example:
(defn student-id-v1?
[id]
(re-matches #"[a-z]{2}[0-9]{6}" id))
;; if match: return match => true
;; else: return nil => false
(defn student-id-v2?
[id]
(if (re-matches #"[a-z]{2}[0-9]{6}" id)
true
false))
I’d do something like this..
(def student-id-v1?
(comp some?
(partial re-matches #"[a-z]{2}[0-9]{6}")))
Thank you for the suggestion ☺️
@UR5QE2DUZ The overall approach is to return a value or nil instead of returning true or false. The former works the same in tests but it is more useful in other places as well.
@UFHE11C83 I see. So I can also use such function like this in spec, right?
(defn student-id-v1?
[id]
(re-matches #"[a-z]{2}[0-9]{6}" id))
Ya, i think this is simplest and most understandable.
This wouldn’t really be conforming the style guide though: https://github.com/bbatsov/clojure-style-guide#pred-with-question-mark
It states that if a function ends with a question mark, it should always return a boolean. This is also common practice in Ruby. Even though nil
and false
are both falsy values, they aren’t really the same.
I found this discussion under the ticket https://clojure.atlassian.net/browse/CLJ-2141 @UG9U7TPDZ Is there any advantage to use a transducer like in your example over something like that?
(defn student-id-v1?
[id]
(comp some?
(partial re-matches #"[a-z]{2}[0-9]{6}")) id)
Not sure what you mean by that? You mean using defn vs def + comp? My example isn’t a transducer. It’s just a value that composes. I personally find it much simpler, and if you want to show the reader what the input is (id) you could write a spec (which is recommended). And just for clarity, this as a transducer would look like:
;; The transducer
(def xform
(comp (map (partial re-matches #"[a-z]{2}[0-9]{6}"))
(map some?)))
(transduce xform conj ["invalid-id" "ab123456" "another-invalid-id"]) ;; => [false true false]
Notice that the functions are reversed, and wrapped in map (because a transducers acts on a stream of data)
Anway this question wasn’t really about transducers but I thought I’d try to at least clarify 🙂can you help me with walkable library? I managed to get a "floor-plan" that is created correctly. I wrote a simple query:
(def my-query [{(:person/all {:limit 5}) [:person/name :person/surname]}])
When I try to print it I get
[{nil [:person/name :person/surname]}]
What should I do to get a query string to pas it to jdbc/query? Or does it work other way? I suppose there should be some function for that in walkable library but there is nothing about executing queries in it's docskeywords are not magic, when you use ()
to run them as functions, they look themselves up. Looking up :person/name
in that map returns nil, as it should
Thank you for the suggestion ☺️
I'm curious on how you folks approach understanding a function's arguments. If you see something like (defn foo [user])
or [name]
or just [input]
how do you begin parsing that? I think that's the one thing holding me back the most by reading other's clojure code. I try other languages and always run back to clojure but the one thing I miss from statically typed languages is an explicit function signature with inputs and outputs.
@chase-lambert
I think it really depends on who writes the code. I agree though, that’s probably the thing I miss the most in Clojure. When writing Haskell / Elm it’s really clear what goes in and comes out. Clojure has spec
which helps a bit in this case, but it’s not a de-facto standard to use it. Also it’s a lot more clutter than a simple type signature (specs are much more expressive, but it hurts readability).
I think what goes a long way is naming conventions for functions.
user->id
Convert (`->`) a user to id
user-activated?
Check if a user is activated, MUST return a boolean (`?`)
set-user-name!
Modify user name state (`!`) (for example an atom)
It’s clear that these functions convert, check, or modify users. But what a user is, is up to the application. Having simple functions like this does help (In the style guide it’s suggested 5-10 LOC https://github.com/bbatsov/clojure-style-guide#function-length). If a user is specced in the namespace, it’s quite clear what defines a user.
This does seem to be what I've gathered most people are doing. I was wondering if something like this:
(defn power
"exponent calculation. takes two numbers, returns a number"
[base exp]
(reduce * (repeat exp base)))
would help at all as a quick example. Or maybe other clojurists would hate that. Just use the doc string. But whenever I try to put something like a map in there to show the shape of expected input I think the compiler or repl doesn't like it because it's trying to read it maybe?I often put a (comment ...)
form directly below a function definition if it's particularly confusing and eval-to-comment on sample data, just as a reminder of the input and output shapes
IMHO, if you start writing in the comments what the arguments / return values are, then just write a spec. Then you actually have a testable case, which will fail if the input / output changes. A docstring can become outdated if not maintained
That is a good idea. I know many people have that comment form at the bottom of their source files for stuff like that too. What about actual type annotations? I know for performance reasons you sometimes have to do (defn foo [^String s])
but can you do that for things like maps or other non primitive types?
I do like pre
and post
conditions like your style guide link mentioned too. Do you think that would frustrate maintainability too?
Also, slightly on topic, when it comes to function name / doc / body
Function name: WHAT does the function do (e.g. user->id
converts a user to id)
Function body: HOW does it do it? 5-10 LOC shouldn’t be too difficult to understand how something is done
Function doc: WHY is it doing this? Maybe there’s a specific business case for this function, to prevent a bug, performance optimization, etc
Though this standard is not really a clojure thing, it’s what I try to use as a guideline. It’s mostly just preference
I don’t think that’s really a bad thing. If the data going through isn’t conforming the spec, might as well fail (it failed somewhere already anyway)
For "function signature" purposes how would you see spec vs pre/post conditions in the function itself? When reading clojure code I don't think I see too much pre/post conditions or anything throwing exceptions (I am not confident in error handling at all tbh) for that matter. I don't run across spec either though. Maybe most just don't have a problem parsing expected input/output
I think specs are the better choice. Spec has a nice toolset for checking what’s wrong. For example if the user
map is missing a key, spec can help you with finding out exactly what it is. So it helps with understanding error messages. I’m not sure pre/post really shines in this area. (I don’t really use pre/post much myself)
Sounds good. I've been very curious about it anyways. I always wonder if I will gravitate to static typing mostly because I just don't seem to advance much in Clojure (or programming in general, but this is one of my excuses) yet I just don't enjoy other languages as much even if I can understand what's going on better. Maybe spec will let me get the best of both worlds.
Also I think spec
would be a better choice since it doesn’t directly influence your code. pre will crash your function call if incorrect data is supplied. If you want that to happen then it’s fine.
I see others mention often that they just like to use spec at the "boundaries" so I do want to keep exploring other techniques to understand more what the functions are expecting and doing because I might not have it available when reading other's code. Thanks for the chat!
Hey all! I think I may have found a bug in clojure.... Can anyone explain why this loop terminates?
(let [xs (map volatile! [1 2 3])]
(loop [seen? #{}]
(let [hash (map (comp inc deref) xs)]
(if (seen? hash)
hash
(do (doseq [x xs]
(vswap! x inc))
(recur (conj seen? hash)))))))
I noticed that it specifically requires xs
and hash
to be lazy sequences - which seemingly causes all set members to become the same.
Is it because the map
on xs doesn't cache values? So then the xs are actually different each recursion of the loop?
Hmm actually it looks like:
(let [xs (into [] (map volatile!) [1 2 3])]
(loop [seen? #{}]
(let [hash (map (comp inc deref) xs)]
(if (seen? hash)
hash
(do (doseq [x xs]
(vswap! x inc))
(recur (conj seen? hash)))))))
terminatesSo it's specifically hash
being lazy. Collecting it into a vector or something causes it to never terminate
I know... same behavior with atoms too
That's not very helpful...
What are you trying to achieve?
I get that I can solve it without mutation
That's not the problem
so when the lazy reading will get different values depending on if it is forced before or after the mutation
at the very least limit your mutation, wrap the source collection in a single mutable reference instead of a mutable reference per element
I guess I'd potentially expect invoking conj
onto a set to check whether something had been realized?
and if not, invoke it
switching your initial collection to a vector like you did sort of looks like it fixes things, but horrifyingly will break things once you exceed 32 elements
I understand that these aren't idiomatic ways of solving things. If this is the intended language behavior, then that's one thing - but I somehow can't imagine the utility in having sets not realize the values of lazy sequences on conj
or their IFn
invokation.
true true
so the values you are conj in, are not what the values would be if the empty set actually had to traverse the lazy seq to determine if its contents where contained in it, which it does not
That makes sense
the reason switching to a vector sort of seemed to fix things is switching to a vector got you a chunked seq, in which case map is only lazy in chunks of 32
Putting mutable objects inside of immutable collections is kind of a red flag here, too, isn't it?
doall
works
(on the hash, which makes sense, because it caches its values)
Oh, I guess the set isn't getting mutable objects put inside of it, never mind.
This bug makes sense now, and is indeed not a bug in clojure at all. Damn, thought I got one. Thanks for the help @hiredman
(and all)
I cannot for the life of me get Clojure code blocks working in Org Mode
Looks like the main issue is a code block can't connect to a running cider nrepl