This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-10-09
Channels
- # 100-days-of-code (6)
- # announcements (4)
- # atlanta-clojurians (1)
- # aws (1)
- # beginners (65)
- # boot (21)
- # cider (9)
- # cljsrn (3)
- # clojure (186)
- # clojure-android (4)
- # clojure-conj (1)
- # clojure-dev (12)
- # clojure-germany (3)
- # clojure-italy (8)
- # clojure-nl (1)
- # clojure-russia (32)
- # clojure-spec (19)
- # clojure-uk (41)
- # clojurescript (83)
- # core-async (5)
- # cursive (18)
- # datomic (15)
- # emacs (5)
- # events (4)
- # fulcro (7)
- # hyperfiddle (4)
- # leiningen (4)
- # liberator (1)
- # off-topic (65)
- # overtone (4)
- # pedestal (5)
- # perun (1)
- # planck (3)
- # re-frame (1)
- # reagent (3)
- # rum (5)
- # shadow-cljs (8)
- # spacemacs (19)
- # testing (3)
- # tools-deps (4)
- # yada (6)
I'm studying (source loop)
in CLJ 1.10 (also at https://github.com/clojure/clojure/blob/master/src/clj/clojure/core.clj). When its parameters involve destructuring, it puts values into vs
, left side (symbols to bind) into bs
:
let [vs (take-nth 2 (drop 1 bindings))
bs (take-nth 2 bindings)]
Then it's magic. Could you help me understand the rest, please.@peter.kehl Can you be a bit more specific about which lines you don't understand? (you can link to specific lines in a file on GitHub which makes it much easier for the rest of us to follow your questions)
https://github.com/clojure/clojure/blob/master/src/clj/clojure/core.clj#L4579 for example
and https://github.com/clojure/clojure/blob/master/src/clj/clojure/core.clj#L4582-L4586 for a line range
@seancorfield The unclarity comes from how destructure
works for destructurable bindings. (destructure '[a 1 b 2])
is easy, it returns [a 1 b 2]
. But what does its result mean for destructurable bindings, please?
(destructure '[[a b] [1 2] [c d] [3 4]])
;====>
[vec__340 [1 2] a (clojure.core/nth vec__340 0 nil) b (clojure.core/nth vec__340 1 nil) vec__343 [3 4] c (clojure.core/nth vec__343 0 nil) d (clojure.core/nth vec__343 1 nil)]
Ah, I see. vec__XXX
are helper bindings to get the actual result binding composed.
Thank you
After destructure
, how can it be possible for some "left" sides (0-th, 2-nd, 4-th entry in the result of destructure
) not to be a symbol
? When you call (destructure '[:keyword-literal 1])
or (destructure '[:keyword-literal 1])
, either fails.
What could make b
be a non-symbol in https://github.com/clojure/clojure/blob/master/src/clj/clojure/core.clj#L4582-L4586, please?
looking...
(let [...
bs (take-nth 2 bindings)
....
bfs (reduce1 (fn [ret [b v g]]
(if (symbol? b)
(conj ret g v)
(conj ret g v b g)))
[] (map vector bs vs gs))]
Interesting that it doesn't use the result of calling destructure
if that returns something other than its input argument.
So the bindings
being used in the code above would be the original bindings, including the destructuring forms...
...so those won't be symbols, e.g., (loop [a 1 {:keys [x y]} input] ...)
Here a
is a symbol?
but {:keys [x y]}
is not.
so you get a binding vector that has [... g__123 input {:keys [x y]} g__123 ...]
-- in other words, it delegates the actual destructuring to the expanded code.
Does that help @peter.kehl?
Oh... I assumed it used result of destructure
- I should have searched for db
.
Yes, interesting. Thank you @seancorfield
In Clojure, that would evaluate both "truthy" and "falsy" first, then return one of them. It differs from Clojure's if
in that way -- if
only evaluates one branch, not both, which is important if there are side effects in one or both branches.
((oif (println "truthy") (println "falsy")) (> 2 1))
would print both "truthy" and "falsy"
with some little adjustments I could make "oif" work, so don't give up on that...
The only other way I can think to approach it (in ClojureScript) involves yet another special form.
(js* "~{}?~{}:~{}" true 1 2)
yeah I don't get it either. map literals and defn
are "special forms", aren't they
FWIW, using a technique like this is the way the and
macro in ClojureScript can generate extremely compact / efficient JavaScript for some kinds of tests (without using if
)
it evals both when creating that map
you need some way to signal to the evaluator, "don't eval this bit" - which necessitates a special form
at any rate, I imagine if you want to pass in a map of things that you are okay with evaluating every option, otherwise it makes more sense just to use condp
and call it good
condp uses cond which is a macro. I would like to know what is allowed in this challenge
Perhaps if you are allowed to use Java or JavaScript you could do something, but that feels like cheating
yeah exactly, so you need to get down into the underlying host logic of short circuiting, which needs a macro somewhere in there to call out to the other thing. Or wrap Java(Script), yeah. Unless you made all the hashmap values into functions to invoke
I didn't know that macros were forbidden so my solution was this
(defmacro my-oif [expr a b]
`(({true (fn [] ~a)
false (fn [] ~b)
nil (fn [] ~b)}
~expr)))
try it with
(my-oif (< 1 2)
(do (println "truthy")
:truth)
(do (println "falsy")
:falsy))
And in case anyone was wondering, there are lazy evaluation languages like Haskell where not just if statements, but everything is lazily evaluated, not strict like Clojure evaluation is.
I've always wondered, what's the advantage of using Haskell over Clojure? Which usecases, etc
I haven't used Haskell enough to give a good answer. Some people really prefer compile-time type checking, and a strong type system that knows the difference between pure functions and side effects, and Haskell can give you that.
There was a recent discussion thread I saw asking "Why do you prefer Clojure over Haskell?" that may have some clues for why someone would prefer that way. As such discussions sometimes go, there is sometimes more heat than light: https://clojureverse.org/t/why-do-you-prefer-clojure-over-haskell/1967/46
maybe the no-special-forms stipulation is related to being able to partially apply/compose it, in which case there are options
the thing is, I can't remember the last time I used if
on a boolean arg, most of the time my "true" case is some random non-nil non-false value that also isn't strictly true
You can wrap the (< 1 2)
or whatever condition in (boolean (< 1 2))
to get only true
or false
out.
Or... I thought you could. Maybe not.
OK, I think you can, but I was temporarily thrown off by the reflection warning message in the REPL I was testing in, believing it was an exception, not just a performance warning. You can use boolean
that way.
i have a command line app written in clojure and built using lein. I would like to include the git revision of the git repository the tool was built from in the command line help page (something I’ve done in other languages in the past and I find it very helpful) for the tool. I.e. I would like to have programmatic access to the git revision in my project code. Essentially this is the build-time domain reaching into the project code…in my past life I would have done this via a generated class. I did a quick search and none of the leiningen plugins I found seem to do this, any thoughts? (reposting from #leiningen as that channel seems a bit slow)
if you are building in some build server kind of thing, usually there is some facility to pass this kind of information as environment variables in the build
I would prefer jgit to a shell exec, but I think my main hickup is with the mechanics of source generation…though I think I just found a useful link: http://hugoduncan.org/post/generating_source_with_leiningen/
just write a clojure program that does what you want, then invoke that program using lein run -m