This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
It appears I understand evaluation less than I think I do. I'm unable to explain this:
user=> or
Syntax error compiling at (REPL:0:0).
Can't take value of a macro: #'clojure.core/or
user=> @#'or
#object[clojure.core$or 0x1e53135d "clojure.core$or@1e53135d"]
user=>
Isn't @#'or
taking the value of or
?
Edit: I thought when I typed-in or
at the REPL, it's first qualified to clojure.core/or
, which is then looked up in the namespace bindings to find #'clojure.core/or
, which is then derefed. I expected that to fail, but @#'clojure.core/or
seems to work.
How is symbol evaluation different in this case?Seemed like an interesting question and went source hunting. Here is what I concluded, the isolated or
and (deref (var or))
take different paths in the compiler. The isolated or
throws at analyzeSymbol
with that error since, I’m guessing, returning a value of macro definition in isolation at any other time than macro-expansion time doesn’t make sense. This is thrown before the namespace->var resolution can happen which is at run time (the var for the symbol is registered with the ns during analyzeSymbol
, but only at runtime does it get derefed). Whereas (deref (var or))
will be routed to analyzeSeq
and (var or)
will not throw and is able to be successfully derefed. But the value of @#'clojure.core/or
itself isn’t of much use at runtime (in contrast to macro-expansion time).
(@#'clojure.core/or 1 2)
=> nil
The throwing of symbols that are macros in isolation during compilation seems to be an explicit choice if not for which the result of typing in @#'clojure.core/or
and or
would’ve been the same.
analyzeSymbol: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java#L6772
analyzeSeq: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java#L6793Thanks for this Q @U883WCP5Z and the A, @UMPJRJU9E.
I'd also gone down the REPL a bit and I got to indy's point of (@#'or true false) => nil
. That led me to suspect the behaviour jaihind observed had something to do with whatever happens prior to allowing the object to be invoked. And de-referencing the var would bypass whatever check was in-between.
I didn't go as far as indy did, though --- thanks for the digging!
One clue that I wanted to follow is that macros have :macro true
in their metadata. Whereas defmacro
is just a fn
. Meaning, macro definition would create an object type indistinguishable from a "plain ol' fn", unless it also added some other distinguishing information that the compiler and/or runtime could use.
Thanks @UMPJRJU9E! I suspected it was being done in (symbol-) analysis but didn't take the time to read the code.
Background of how I discovered this oddity (only in case someone's interested):
I was mentoring someone on exercism (https://exercism.org/profiles/jaihindhreddy) and they asked if we could programmatically get a list of the test-cases from the tests.
I took a crack at it using with-redefs
and found it didn't work for macros. In addition, weirdly enough, using with-redefs
with macros permanently removes :macro true
from the var metadata.
Turns out there's a ticket for it already (https://clojure.atlassian.net/browse/CLJ-1867)
Here's the code I initially wrote:
(defn- get-test-inputs [ns test-ns]
(let [cases (atom {})
;; returns the fn of a var, wrapped to put args in `cases` first
wrap (fn [var]
(let [sym (symbol var), f @var]
#(do (swap! cases update sym (fnil conj []) (vec %&))
(apply f %&))))]
(with-redefs-fn
(->> (vals (ns-publics ns))
(remove (comp :macro meta))
(map (juxt identity wrap))
(into {}))
#(binding [clojure.test/*test-out* (java.io.StringWriter.)]
(clojure.test/run-tests ns test-ns)))
@cases))
After observing weird behaviour with macros, I looked at (source defmacro)
and found that macros functions have two implicit args i.e, the form, and an env
variable, which has binding
s.
I updated wrap
above, and then ran into https://clojure.atlassian.net/browse/CLJ-1867.Nice! Thanks for the detail! TIL https://github.com/clojure/clojure/blob/5cfe5111ccb5afec4f9c73b46bba29ecab6a5899/src/jvm/clojure/lang/Var.java#L270, as triaged in that ticket.
i have to list (1 2 3) (4 5 6) I want to arrange them in the form of (x y) cordinates like [[1 4] [2 5] [5 6]] how can I do that
thanks brother
Please do not cross-post questions like this to #clojure as well -- just ask them here.
Hi, I'm doing some problems on codewars and I saw this solution from another player
(defn get-sum [a b]
(->>
(if (> a b) [b a] [a b])
(#(range (first %1) (+(second %1) 1)) ,,,)
(reduce +)
)
)
What is the ,,,
doing here ?I've noticed some people put the trailing )
on their own lines too. Dont think I like this style.
But maybe it makes it easier when putting cursor to correct bracket for eval'ing stuff
I most commonly see it used in Rich comments:
(comment
#_(some-debug-stuff ...)
,,,)
I quite like this pattern, since it makes the "commented out" nature of the form stand out a bit moreI have a list of number [1 2 3 4 5 6] I have to create a function which return closest smallest number to the argument lets say I passed it 6 and it returns me closes largest number 5
Is the list sorted? And what do you mean by closest? Do you mean closest in magnitude, or closest in position to the number 6 in the list?
check out the min-key
function @U02DQ45FQF9
closest in mangitude
SOmething like this:
(defn smallest-closes [xs target]
(->> xs
(sort)
(map (fn [n] {:v n
:d (Math/abs (- n target))}))
(filter (fn [{:keys [v d]}]
(not= 0 d)))
(sort-by :d)
(first)
:v))
(smallest-closes [10 12 30 31 35 36] 34) => 35
(smallest-closes [10 12 30 31 35 36] 33) => 31
(smallest-closes [1 2 3 4 5 6] 3) => 2
(smallest-closes [1 2 3 4 5 6] 6) => 5
(defn closest-smallest-unsorted
[v num]
(second (reduce (fn [[diff res] el]
(let [new-diff (Math/abs ^long (- num el))]
(if (and (< el num) (< new-diff diff))
[new-diff el]
[diff res])))
[Long/MAX_VALUE nil] v)))
(defn closest-smallest-sorted
[v num]
(reduce (fn [prev-el el]
(if (= el num)
(reduced prev-el)
el))
nil v))
No need to sort the collection:
(apply min-key #(Math/abs (- % target)) coll)
is there any way to round or floor numbers ?
would converting into integers work? You could use int. There's also Math/floor and Math/round.
"core" thru me at first, but like any language computer or human there are idioms, and these quickly gain their correct semantic as we grow into the language. I am with you, to me core means utility. Now my practice is to use "base.clj" for super-low-level stuff that everything will need.
Hello! I just started experimenting with clojure, clojurescript and krell. This is my first time working with clj tools. I'm using neovim as my editor and have successfully connected nrepl to neovim using the conjure plugin. Now I would like to connect the krell repl to conjure. There is this documentation in the Krell wiki https://github.com/vouch-opensource/krell/wiki/Tooling-Integration---Emacs%2C-Cursive%2C-VSCode-etc... I just don't understand where I should put these lines of code... Here is the Conjure documentation https://github.com/Olical/conjure/wiki/Quick-start:-Clojure
I am able to start the normal Krell repl from the command line.
Is there a way to use something like &rest
when destructing a map to get the remaining key/values in an object? Like:
(let [{myKey :myKey
restOftheObject &rest}]
(println myKey restOftheObject))
Just use :as
and pass the whole map.
If for some reason you really have to exclude certain keys, you can do it with dissoc
I feel like I’m getting lost in tree structured let
blocks by checking errors before I call subsequent functions. How can I, if possible, write this better?
Here is a wrapper around a compojure/ring route that handles file uploads with parameter validation and file-storage. If those succeed, it will call the callback argument with some data from the previous step and request body.
If any step fails I need to return a response map for Ring, but I’m not sure the best way to do error checking without doing a let block for each error.
(defn file-upload-wrapper
[controller config callback]
(wrap-multipart-params
(POST controller request
;; Validate request body - returns null or error message
(let [error (is-valid-req (:params request) config)]
(if-not (nil? error)
(bad-request error)
;; If no error, store file and check error
(let [[filepaths error] (store-files (:params request) config)]
(if-not (nil? error)
(bad-request error)
;; If no error, call callback with metadata
;; Check if error occurred in callback??
(callback (agg-metadata (:params request) filepaths) request)))))
(response "OK"))))
You can streamline that a bit by using if-let
instead of let
/ if-not
/ nil?
-- if error
is either truthy or nil
, you can rely on nil
-punning.
(if-let [error (is-valid-req (:params request) config)]
(bad-request error)
...
You can't do much about the second let
but saying (if error ..)
rather than (if-not (nil? error) ..)
would be more idiomatic (and a lot more readable for others).
I would probably extract the validation to a function and have it do both checks. Then you could at least have:
(let [[filepaths error] (validate-and-store-files (:params request) config)]
(if error
(bad-request error)
(callback (agg-metadata (:params request) filepaths) request)))
(It's unclear to me what your (response "OK")
is supposed to be attached to since I would have expected (bad-request error)
to return an error response to the caller?)Hmm, I think you're always returning (response "OK")
and so bad-request
is just logging that an error has occurred? Seems odd to me but, OK.
No, you’re right. the response "OK"
placement is a bug. It should be that if the callback returned without error, it would respond OK.
I thank you for the tips and pointers. I will implement them as fit. Instead of error checking each fn, would it be better to wrap it all in a try/catch and throw an error from the called functions and just handle check the error once in a catch?
Well my feeling on exceptions is that they should only be used for unexpected conditions. If you're validating input, you expect it to be wrong sometimes and you explicitly handle that.
is their a threading macro where it only keeps going as long as a predicate passes. e.g. an equivalent to something like this where M1, M2, M3 etc returns an Either.
M1().Then(M2)
.Then(M3)
.Then(M4)
.Match(left: HandleFail
right: HandleSuccess)
If say, M2 returns a Left in the Either, then it won't execute M3 and M4...
So something like
(???-> (m1)
(= 5) (m2) ; if m1 returned 5, do m2
(= "hotdog") (m3) ; if m2 returned "hotdog", do m3
) ; etc
Take a look at some->
I'm trying to call clojure.java.shell
and pass it the command rm
(WIndows, powershell) and a file to delete. However, I keep getting that it can't find the file specified.
Similar calls (sh "ls")
, returns the same error. Can't find the file. Same for (sh "pwd")
> java.io.IOException: CreateProcess error=2, The system cannot find the file specified user c:\Users\stuarts\Source___TESTREPOS__Clojure\create-dotnet-core-repo\create-dotnet-core-repo.clj:1:1
Yet, calls like (sh "dotnet")
works just fine, or (sh "notepad.exe")
fires up notepad. Is their something in particular I have to do when dealing with system commands ?
You have to open a shell first
(sh "cmd" "/C" "dir")
(sh "powershell" "/C" "dir")
@qmstuart clojure.java.shell
doesn't mean that you can execute unix shell commands on Windows: it simply shells out to the programs on your computer, so it's not a cross platform tool that tries to emulate bash or anything
If you are using #babashka and you want to remove files or list files, I suggest taking a look at babashka.fs
ah ok! That's exactly what I want to do, just delete a file in my script as some tidy up, so I'll look at babashka.fs
, thanks for your help!
The docs are over here: https://babashka.org/fs/babashka.fs.html Feel free to join #babashka if you have more questions
(I realized you were already in there, sorry, context switching made me forget this :))
thanks, I got this all working. At work we have 3 main project types, C# dotnetcore, dotnet framework and golang. I've written myself a babashka script that I can feed in a project name, repo name for each project type and it makes me a repo on our github, pulls it, modifies the build and release.yaml so that it builds and uses some of our in house github actions, sets up versioning, issue templates etc, all from one command. It's going to save me so much time, babashka is really great! And the workflow with it connected up to Calva via the bb repl is wonderful. Now, do I show people at work it or keep it my secret... If I show them they will want it, but they will want it rewritten in C# or go...
I'd say show them and since it's your personal helper script, you would want to share it but on the condition that you can maintain it in your language of choice ;)
to connect to the repl, im doing bb -nrepl-server 1667
, then going into Calva and connecting to that repl via connect to running repl, Is that the correct way ?
yeah, I think so, although calva might also have a jack-in command for that, but this is fine
is this revenge of the hyphens / underscores?