This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-03-18
Channels
- # beginners (123)
- # boot (3)
- # cider (6)
- # clara (1)
- # cljs-dev (139)
- # cljsrn (9)
- # clojure (59)
- # clojure-italy (5)
- # clojure-uk (41)
- # clojured (10)
- # clojurescript (67)
- # community-development (1)
- # component (2)
- # core-async (7)
- # cursive (4)
- # datomic (4)
- # defnpodcast (2)
- # fulcro (23)
- # graphql (1)
- # jobs (2)
- # leiningen (4)
- # off-topic (32)
- # portkey (7)
- # protorepl (5)
- # re-frame (19)
- # reagent (5)
- # reitit (23)
- # shadow-cljs (29)
- # slack-help (1)
- # spacemacs (1)
- # tools-deps (21)
- # unrepl (18)
Hi, which is the good way to transform vector of maps to map of vectors? Ex: [{:a 1 :b 2} {:a 2 :b 3} {:a 3 :b 4} => {:a [1 2 3] :b [2 3 4]}]
@rauh @tap Thank you, that's better. I have made it with redude-kv `(reduce-kv (fn [m k v] (merge-with into m (reduce (fn [newcoll [x y]] (assoc newcoll x [y])) {} v))) {} [{:a 1 :b 2 :c 3} {:a 2 :b 3 :c 4} {:a 3 :b 4 :c 0}])`
hey, I'm reading about seq functions and.. isn't calling into
after every call horribly expensive?
@mailmeupinside Only way to find out is to benchmark it. Comparing it with conj
@rauh yeah, but I see that clojure does a lot of conversions between the types. maps into sets, then lists, then maps again and I'm used to doing everything using just one type
Why does
(defmacro domain
[name & body]
`{:content [~@body]})
and
(defmacro domain
[name & body]
`{:content ~(vec body)})
work but not
(defmacro domain
[name & body]
`{:content ~body})
@ackerleytng It does, in a sense. Try (domain foo inc 10)
for a clue 🙂
You can change your last definition to
(defmacro domain
[name & body]
`{:content '~body})
if you want to imitate the first two.oh! so ~
sort of executes what comes immediately after
hence (inc 10)
becomes 11
?
'~body
results in (inc 10)
being spliced in
It unquotes. To see this try (def a :hi)
and then
`a
and then see what happens when you unquote
`~a
Yeah, but I wouldn't use the word splice for '~body
, as that meaning is applicable to your form [~@body]
.
hmm ok
what does unquote really mean?
does it mean...
"allow eval to really happen"?
'
means "for the next form, don't do anything and just pass it on exactly"
It means not much more than "unquote", but of course a consequence is that the evaluation can occur
as in this?
learning.core> '(a b c)
(a b c)
So that describes the low-level mechanics. But, in the end, it has the effect you are describing. It punches a hole in the quoted "thing", and lets the unquoted bit through so that it can be evaluated instead of being quoted to prevent evaluation.
learning.core> `(a b c)
(learning.core/a learning.core/b learning.core/c)
what's the difference between a
and learning.core/a
?
"qualifies symbols" means taking symbols and attaching a namespace to it?
a
by itself is a symbol that (if not a local via let
or a function argument), would resolve to the namespace it is in when evaluated
An example. If you
(def inc 3)
then inc
resolves to user/inc
and evaluates to 3
. But clojure.core/inc
can still be used to refer to the core function.So, if you are in the learning.core
namespace a
and learning.core/a
would be the same (assuming a
is not a local or fn arg)
thanks 🙂
so
`a
sort of halts the evaluator?cos it
learning.core> `a
learning.core/a
doesn't go ahead and resolve learning.core/a
so is it something like read resolve eval print loop
and ' halts resolving (and eval)
but ` halts eval?
yes, why have a syntax quote to qualify symbols?
To fix that (make your macro hygienic), you might write (defmacro my-inc [x] (list 'clojure.core/inc x))
even macroexpand-1 immediately prints 11
i was expecting it to print (inc 10)
Did you forget to quote the argument to macroexpand-1
? You need to do (macroexpand-1 '(my-inc 10))
oh yes i did sorry
yes, it returns 3 instead
(letfn [(inc [x] 3)]
(my-inc 10))
so the difference between defn
and defmacro
is that defn
returns the result
and defmacro
returns something that will first be evaluated, before the result is printed
@mfikes already said this, but let me try to put it in different words. Macros are functions that you are sticking into the compiler pipeline. When the compiler reads an expression like (do-something some-value), one of the first things it does is look for a macro called do-something. If it finds a macro called do-something, the compiler will evaluate macro just like a function, passing in the code for the arguments - so in the example it will pass in some-value. The result returned by the macro is what the compiler compiles. So a macro is free to generate code that evaluates its argument, munges them somehow or ignores that completely. And if the macro ignores its arguments then they effectively disappear, since the compiler never see them.
Just to finish the story, if the there isn't a macro called do-something then it's either a built in thing like 'if' and the compiler will generate code for that built in thing or it will generate code to evaluate the argument and call a function called do-something.
Thanks!
But instead if you were to have defined my-inc
using (defmacro my-inc [x] (list 'clojure.core/inc x))
it would work and return 11
yes this is right
yes this is right
Think of defn
as def
ing a function that you can call at runtime. Think of defmacro
as def
ing a function the compiler calls at compile time (during macroexpansion)
how about
(defmacro my-inc [x] (list inc x))
? it seems to work tooThis is because your last macro example is returning a list containing the value of inc
(either the function value or the number 3
depending on what you have done)
i see
thanks @mfikes, really appreciate it
i guess i'm still not completely clear but i'm better than before, thanks again!
hi, beginner here, i started by editing clojure using parinfer in atom. now i am trying to learn how to code clojure in spacemacs. should i try to install parinfer there as well or should i get used to smartparens? as i understand it, to get parinfer to work in spacemacs i have to switch to the develop branch which may be more unstable.
Hi! How much experience do you have with emacs in general? How much experience do you have with programming?
I'm interested in this question as well. I am experienced in programming and emacs with evil-mode
@U6GNVEWQG i’m an experienced python programmer. i’m fairly familiar with vi, but almost no experience at all with emacs.
one reason i was attracted to parinfer at the start was because it allowed me to edit clojure like it was python, where i basically don’t have to think about the parentheses
Yeah, your background is similar to my own when I started. I was using vi and atom/vscode. If I had to go back, especially when just learning clojure, I wouldn't even worry about parinfer. Just focus on the code and, if you want, a strong REPL environment. The tooling took way to much of my time in the beginning.
Especially if emacs is not your your regular tool of choice. There is enough to learn in Clojure that I would strongly recommend using a simple editor like Atom. Prototepl is great. The other tooling that you will hear experienced clojurists talk about is amazing, but keep in mind, they have the experience and it comes a little more naturally.
Again, this is coming to someone who dove into emacs without much experience, fought to make the tooling work and lost track of the original purpose: To rock out with clojure
However, like you said, parinfer is an excellent tool, and I don't want to discourage you from using it, but if your goal is to learn an opinionated editor like emacs, and the tooling that sits ontop of it, and learn a language like clojure, this can be a lot at once
BTW, the spacemacs clojure layer is quite good, doesn’t have parinfer but it does have rainbow parentheses (I think by default) which goes a long way towards helping you balance parens.
I've used both smartparens and parinfer (in Spacemacs), and although parinfer is excellent, I've ended up sticking with smartparens. The key is to use sexp-editing commands as much as possible, instead of just deleting/moving stuff character-by-character. That way your parens will stay balanced at all times.
You may also want to turn on smartparens-strict-mode
, which will force your parens to stay balanced -- that makes it harder to make mistakes.
That said, it's not actually that much of a headache to be on the develop
branch of SM.
Either way, paren-reading and -balancing will stop feeling difficult after a while, so I wouldn't worry much about it -- just pick one or the other and stick with it until parens feel natural.
@U077BEWNQ can you give some examples of how to use the sexp-editing commands? I'm not sure how to use them
Oh, for sure! Most of the stuff I'm talking about is what's under SPC k
-- I use SPC k s
and SPC k b
constantly for slurp and barf.
Smartparens is built on paredit, IIRC, and this page gives animated examples of most of the capabilities (ignore the exact fn names and key bindings, this is just to give an idea): http://danmidwood.com/content/2014/11/21/animated-paredit.html
And the most important one for me is the simplest one, which I do manually -- if I'm going to cut some text in clj/s (or kill it, in emacs terms), I always do it on a per-sexp basis. eg start on the paren at one end, hit v
for visual mode, %
to go to the matching paren, and then cut/kill. That way cutting/pasting text never results in unbalanced parens.
Great! Thanks
@mfikes already said this, but let me try to put it in different words. Macros are functions that you are sticking into the compiler pipeline. When the compiler reads an expression like (do-something some-value), one of the first things it does is look for a macro called do-something. If it finds a macro called do-something, the compiler will evaluate macro just like a function, passing in the code for the arguments - so in the example it will pass in some-value. The result returned by the macro is what the compiler compiles. So a macro is free to generate code that evaluates its argument, munges them somehow or ignores that completely. And if the macro ignores its arguments then they effectively disappear, since the compiler never see them.
Just to finish the story, if the there isn't a macro called do-something then it's either a built in thing like 'if' and the compiler will generate code for that built in thing or it will generate code to evaluate the argument and call a function called do-something.
does anyone know a good clojure boilerplate project for server side? with endpoints and all..Ideally that uses datomic.
I would take a look at Luminous for something that helps you at least start to wire things together. not sure it has a datomic plugin, but probably does.
It does, but it treats Datomic like any other «mutable» database, which is a bit suboptimal IMO
How do I append a string to a list? cons/conj and friends all seem to append each character in the string individually to the list, which is not what I want to do
@samcgardner (conj ["foo" "bar"] "baz")
.
Yeah, follow-up question. Why does (conj (list "a" "b") "apple") get me [a, b, c, p ...] but working with a vector gives the expected result?
It was caused by using a list rather than av ector
But I'm not clear on why this would matter
Err, that's an utter lie. Conj works but prepends rather than appends on list
I think I was using cons or list* to try and append
Also conj works in a type-specific way, adding elements where they're most efficiently added -- which is different for lists (prepending, since they're linked lists) and vectors (appending).
I guess I'll just try and internalise the idea that vectors are my friend
@samcgardner you've got the right idea, usually the only time you deal with lists is when you're doing macros
Yeah I didn't realise vectors coped well with appends
Cheers guys ❤️
Note that cons
is different, it behaves the same on lists and vectors.
user> (cons 1 [2 3])
(1 2 3)
user> (cons 1 '(2 3))
(1 2 3)
If I were hellbent on appending (not prepending) a string to a list, what would I do? (cons string list) ?
err, (reverse (cons string (reverse list)) even
hey everyone, I am trying to setup a project using datomic, and even tho I have few dependencies I keep getting errors related to conflicts and so when I run lein deps :tree
it suggests me to add some excludes
, I added them, but it keeps asking me to add mpre. Am I missing some sort of good practice? is it normal to add so many excludes
?
I am a complete newbie, but is this a decent way to shuffle a string? (clojure.string/join (shuffle (seq "abcdefg")))
that's how i would do it. just searched for how to do it in Java, and doesn't seem there's a better way on that end either
Thank you
seq
can be omitted in this case and another common idiom is to apply
str
in lieu of clojure.string/join
:
(apply str (shuffle "abcdefg"))
@mfikes Thank you. Yeah, I actually switched to apply
a little while ago to be a bit more concise and not needing to be delimited
This is actually the very first thing I ever coded in Clojure, so nice to know