This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
Regarding the clojure cli: I’m working on a namespace that I intend to invoke via -T
; is there a way to get an nREPL running for it?
Things I can think of:
1. just add it to a src
dir
2. start the nREPL from inside the namespace
3. some combination of cli tricks I don’t know that will load the file and run a REPL. I tried some things using -i
that didn’t pan out
Is the namespace not already in the src
directory of the project? I'm not understanding your project structure based on this. How would you intend to use -T
for code that isn't on a classpath?
the namespace is in the project root; my understanding was that -T
will ignore src
and look in .
and that works
If you're using -T:some-alias
that alias can specify any :paths
you want. Is this just for build.clj
or are you developing something you expect other folks to install via -Ttools install
?
For example, for our build.clj
at work, I start an interactive REPL with:
clj -M:build -i build.clj -e "(in-ns 'build)" -r
but when working on the build.clj
in an editor, I jack-in with :build
as one of the aliases -- and our :build
alias uses :extra-deps
specifically so it combines when using -M
(but will still work as expected standalone with -T:build
).Thanks @U04V70XH6, not intended for distribution, it’s just a simple github webhook handler
Hmm, you might be better off just having it as part of your codebase, under an alias to control the classpath, and using -X
instead -- either way, I think aliases are your friend here.
Following code works
(-> member
:id
(amount-owed-for-expense expense)
(+ amount)
round-to-two)
but following doesn't
(-> member
:id
(amount-owed-for-expense expense)
#(+ % (if (pos? %) 0 amount))
round-to-two)
Any idea what am I doing wrong?
The error is ; IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol
Edit - Refactoring it to a defn also worked
defn- offset-by-payment [total-owed transaction-amount]
(+ total-owed (if (pos? total-owed) 0 transaction-amount)))
if we macroexpand a simpler example:
(macroexpand '(-> 7
#(+ % 2)))
=> (fn* 7 [p1__2521#] (+ p1__2521# 2))
we can see that the macro is a re-write, and when re-writing in this way, it creates a function call that isn't syntactically validI think you need
(#(+ % (if (pos? %) 0 amount)))
lambda functions need to be in parens in a threaded context.
this "wrapping lambdas" is sometimes considered bad form/confusing: <https://stuartsierra.com/2018/07/06/threading-with-style> see the "Don’t use anonymous functions to change argument position" heading (and judge how you feel about it, of course)
Interesting article but to me the lambda-in-parens seems cleanest.
as->
is designed for this situation:
(-> member
:id
(amount-owed-for-expense expense)
(as-> x (+ x (if (pos? x) 0 amount)))
round-to-two)
One thing I was wondering is if there is a core function that takes a 2-arity function and returns a function with its args reversed?
That would be like flip
in Haskell. No, Clojure does not have that.
(funnily enough, that was being discussed in another thread in the past couple of days)
The article doesn't like the inline as->
and I think it's slightly less readable than the lambda-in-parens 🙂
We have a little "Clojure extensions" library at work and I added flip
ages ago but we just stopped using it -- in favor of "plain" idiomatic Clojure 🙂
flip
seems like it could be nice here
that also makes sense I guess
flip
should be core and idiomatic!
In the follow-up article, Sierra says of: > That’s a good use case for as->, but I would tread cautiously even here. as-> subverts the usual pattern of -> and, as such, should be used only in exceptional situations where the alternative is worse.
funny I was thinking about this and googled for "clojure flip" (just guessing it would be called flip
)
So even there, Sierra thinks there are good uses of as->
We don't use it a lot at work but we do use it.
We used to have maybe a dozen instances of flip
in our codebase but over time we just refactored them away as we simplified code -- as part of breaking up long chains of threaded calls.
sort of tangential, but flip
also gets interesting when you commonly have vararg functions and what not
was flip
a macro?
https://github.com/worldsingles/commons/blob/master/src/ws/clojure/extensions.clj#L93-L100
I think as->
is "OK" if you have a long chain of calls in ->
and need something special for one in the middle. If the odd-one-out is at the end, use let
to name the result of the ->
chain and then just write an expression using that name. Same with cond->
or ->>
in the middle of a long ->
chain. But also maybe think about not having that long chain in the first place since it macroexpands to a deeply nested set of calls -- which you'd probably consider a bit of a "smell" and you would break it up and name the pieces.
->
lulls us into a bit of a sense of false security since it "hides" the deep nesting and so we are less encouraged to break our code into smaller pieces.
What's wrong with a lambda in the middle?
(#(..) ..)
you mean? I think you're the first person I've run into who thinks that is readable 🙂
Avoiding that sort of code was the whole reason Rich added as->
(and, boy, were there some long arguments about the naming of that macro!).
People had been clamoring for something like as->
for ages back then...
(if I recall correctly, it was talked about as let->
for quite a while before it became as->
)
(as-> _ (foo _ bar))
(#(foo % bar))
lambda wins for me 🙂You don't need it in that simple case. Just use ->
You don't need it in the #(foo bar %)
case either -- use ->>
I was just comparing the 2 forms on their own
the context of ->>
was assumed 😛
But it's a false comparison. The OP's example was better, since it used the threaded expression twice.
And you can't nest these things in ->>
-- you can't use as->
or ->
or cond->
etc inside ->>
.
sigh. let's drop it here
I can see a temptation to use (#(foo % bar))
inside ->>
but I'd do what Sierra recommends in that case and write a local adapter fn in let
above:
(let [foo-bar (fn [x] (foo x bar))]
(->> ...
(foo-bar)
...))
So my error was that I just created the lambda and didn't evaluate it. Got to learn lot of other good stuff also. Thanks everyone!
It’s interesting to read. I’m a relative newcomer, with just over a year of using clojure for personal tooling. I learned from this slack that it’s considered “smell” to use lambdas in that way and I just use the as->
approach that’s mentioned here. I have no strong preference, so I just went with it. However, I also can be counted among those that find the lambda approach just as readable and comfortable as the alternatives. No idea why.