This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-04-30
Channels
- # babashka (46)
- # beginners (234)
- # bristol-clojurians (4)
- # cider (7)
- # clj-kondo (39)
- # cljdoc (8)
- # cljs-dev (10)
- # cljsjs (10)
- # cljsrn (24)
- # clojure (84)
- # clojure-brasil (7)
- # clojure-europe (12)
- # clojure-germany (4)
- # clojure-italy (3)
- # clojure-nl (41)
- # clojure-spec (17)
- # clojure-uk (66)
- # clojurescript (64)
- # conjure (161)
- # cursive (12)
- # data-science (45)
- # datomic (20)
- # devops (11)
- # docker (2)
- # duct (9)
- # events (7)
- # figwheel (1)
- # figwheel-main (20)
- # fulcro (32)
- # graalvm (5)
- # helix (82)
- # jackdaw (9)
- # jobs-discuss (19)
- # kaocha (11)
- # local-first-clojure (1)
- # malli (6)
- # meander (3)
- # nrepl (12)
- # off-topic (2)
- # other-lisps (15)
- # pathom (14)
- # rdf (6)
- # re-frame (8)
- # reactive (1)
- # reagent (5)
- # reitit (4)
- # rum (3)
- # shadow-cljs (77)
- # spacemacs (3)
- # sql (9)
- # test-check (31)
- # tools-deps (13)
- # vim (62)
- # xtdb (18)
Hi, Joker says my do blocks are redundant, what does it mean?
Hi, Joker says my do blocks are redundant.
What does it mean?
(defn request-rows
[range robot]
(loop [i range]
(when (> i 0)
(do (tags/request-tag (str "ROBOT_" (:id robot) "_ROW_" i "_FISH_CELL_ID") 6000))
(for [feeder (:feeders robot)]
(do (tags/request-tag ((str "ROBOT_" (:id robot) "_ROW" i "_AMOUNT_LEFT_TO_FEED_"(:id feeder))) 6000)))
(recur (dec i)))))
Blessed be you.@ozfraier many clojure macros (including loop, fn, and when,) contain an implciit do
@ozfraier also do with only a single form in it is always redundant
(do x)
can be replaced with x
, in any case where (do x)
is valid
Question about clojure's ==
equality test. so I get that it is equality check with an additional type check, but when I do:
(== 1 1.0) ;;true
(== "X" \X) ;; false
So does clojure consider all the number related data types as same type? But not for strings and chars?@sunchaesk ==
is not exactly =
with additional type checks. For example (== 0 0.0)
is true, but (= 0 0.0)
is false. There are three "numeric categories" that are never equal to each other for =
. See https://clojure.org/guides/equality
That article is for Clojure specifically. And may differ from Clojurescript in ways I do not know
and i'm not trying to be snippy. i honestly didn't know the answer but trying to show you how i knew where to look to find an answer
Oh alright. I was just reading the examples on the clojure community website and I didn't quite get the documentation there, BUt still thxs for your answer
there's nothing in clojure or java that considers "X" and \X the same
you could make your own test function of course #(= (str %1) (str %2))
or more generally #(apply = (map str %&))
Oh alright. I was just reading the examples on clojure docs website, and just had this question while looking at the equality test examples. thxs for answering
@sunchaesk I don't get false
, I get an exception from that second comparison:
user=> (== "X" \X)
Execution error (ClassCastException) at user/eval143 (REPL:1).
class java.lang.String cannot be cast to class java.lang.Number (java.lang.String and java.lang.Number are in module java.base of loader 'bootstrap')
user=>
and the source of it shows it calling into clojure.lang.Number
As @dpsutton says, if you look at (doc ==)
it says that it works with "nums" so I'm not sure how/where you're running that ==
between a string and a character?
Oops I meant exception. No I wasn't using any of the codes but I was just reading the examples on the clojure docs website and just had this question
then even easier i suppose > Returns non-nil if nums all have the equivalent > value, otherwise false. Behavior on non nums is > undefined.
Ah, yeah, cljs having different behavior to clj makes sense(!).
Hello 👋, first time poster. Working my way through Clojure for the Brave and True and confused on the example below. Why does the vector need the extra braces?
(into {:favorite-emotion "gloomy"} [[:sunlight-reaction "Glitter!"]])
; => {:favorite-emotion "gloomy" :sunlight-reaction "Glitter!"}
putting space around them to make them not bleed together. its a vector. each element of which is a two element vector, key and value
the way maps work, the input could have been [{:sunlight-reaction "Glitter!}]
as well - you don't see this form as often though
Interesting, I feel like I see that all the time in JavaScript. An array of objects.
right, a map accepts either a map, or a vector (treated as a key-value pair, must be exactly length 2)
there's also assoc
which takes a freeform series of keys and values
That's the difference and which is pretty mind bending for a humble JS dev learning Clojure.
user=> (assoc {:a 1} :b 2 :c 3)
{:a 1, :b 2, :c 3}
we use maps a lot, so we have many features and conveniences around them
Oh, I didn't know about assoc
yet, wow.
@ozfraier even if when
and for
didn't have implicit do
, your code still doesn't make much sense to me. Why are you wrapping single expressions in explicit do
's? do
is only useful for grouping multiple expressions.
@jason358 I refactored a do block that had multiple expressions into a for block, Also, I felt like I needed the do to run the request-tags
function immediately for side effects, but that may be voodoo programming.
if your expr is in "lazy" context, wrapping it in do
still does nothing, your do
will now be in the same "lazy" context
cf.
user=> (do (for [a [1 2 3 4]] (println a)) 1)
1
user=> (do (for [a [1 2 3 4]] (do (println a))) 1)
1
see, println
isn't evaluated either way, because it's in for
's lazy sequence that doesn't get forcedI think I confused do an doall in that case. What about
(doall (for [a [1 2 3]] (println a)))
?doall
does the trick, but what you are really looking for is doseq
🙂 as in (doseq [a [1 2 3]] (println a))
I dont think so, cause at map order is random.
yeah, before (f)
runs, it is read (to create the symbol inside a list, which eval then compiles and runs), and the reader is what creates the hash map and is allowed to change the order
@hindol.adhya on the other hand: (hash-table :x (f) :y (g))
will always call f before g, since the map is created after eval
@hindol.adhya I would not rely on that. I would go for (let [x (f) y (g)] {:x x :y y})
@teodorlu it's fine to dislike it on style grounds, but it's an explicit promise that args are evaluated left to right
@noisesmith I was referring to @hindol.adhya’s example
Sidenote: if you rely on the order of f and g, they probably have some side effect. I'd consider renaming to f!
and g!
.
@teodorlu I have considered that. They both read from a reader. I ended up not adding !
mostly due to preference.
Yeah, in that case I might agree. Hard to come up with a general rule. Clojure internally isn't 100 % strict on this either, both slurp
and spit
are missing !
and read
and println
and ...
Hello everyone, I wanted to use `comment` macro as java `/ /` analog
(comment
1todo
)
but I got
1. Caused by java.lang.NumberFormatException
Invalid number: 1todo
Is there a way I can workaround this ?I don’t think there is. The reader has to read the complete (comment ... )
form, and it can’t do that if there’s an error inside the form.
If I have a collection of a collection of strings, let's say
[["hello" "world"]["hello" "mars"]["hello" "moon"]]
And I want to call str
on them so I get a collection of strings instead
'("hello world" "hello mars" "hello moon") ;;I don't really mind the type of collection
How do I get there?(map #(clojure.string/join " " %) [["hello" "world"]["hello" "mars"]["hello" "moon"]])
Cool 🙂 actually, the space was not really part of the problem 😅
I came up with (map #(apply str %) [["a" "b" "c"]["d" "e" "f"]])
yep, that'll work too if you don't need the space
@e2d4f6 I use
#_
instead of comment, it's more powerful
user=> #_(1todo)
user=>
user=> #_(1todo)
Syntax error reading source at (REPL:1:9).
Invalid number: 1todo
Syntax error reading source at (REPL:1:10).
Unmatched delimiter: )
user=> *clojure-version*
{:major 1, :minor 10, :incremental 1, :qualifier nil}
@noisesmith Unfortunately it does not work on my side. What clojure version do you use ?
*clojure-version*
evaluates to {:major 1, :minor 10, :incremental 1, :qualifier nil}
also, that error message makes me think you are using nrepl, I bet what you are seeing is an nrepl or reply lib bug
if you are using lein, try lein run -m clojure.main
instead of lein repl
- that won't start a server, but will give you a direct repl, and I bet the form works there
I tried running: - clj - cider - lein run -m clojure.main unfortunately the same result
Syntax error reading source at (REPL:1:9).
Invalid number: 1todo
oh... maybe I had it backward and only my nrepl accepts that :/
yeah, sorry, #_ doesn't accept invalid forms, it looked like it did due to a corner case nrepl behavior for me locally
it doesn't even care about classic issues like unbalanced hash-maps:
user=> #_{1todo}
user=>
and just like comment
, #_
does inline / multi-line commenting
user=> #_{1todo} 42
42
hi, I don't know what is wrong with this:
(comment
(defn destructure [aa] (println aa)
;(let [{:keys [c d]} :as aa]
; (println c " " d " ")
; )
)
(let [xx {:a 3 :b 4}] (destructure xx))
)
it's realy frustrating since I am reading the docs and I can't figure out whare I'm going wrong
In your let
, you don’t want the :as
there.
yeah, the :as belongs inside the hash-map, but aa is already bound, so you don't want it at all
another issue is clojure.core/destructure
exists and wouldn't like your map most likely
I think the code as pasted is fine?
it would be, if that destructure was the one he was calling when he called destructure :D
yeah exactly 😄
you can use *e
to see the full previous error, including stack trace etc.
that's often enlightening
oh i'm sorry. i didn't put together your destructure
. my mind went to clojure.core/destructure
. that's why i said pretend that doesn't exist. i'm sorry for my confusion
eg. the stack trace would have revealed that clojure.core/destructure was called, and not the one in your ns, most likely
ok, so thanks to your help I figured it out - I was loading the whole file in repl - but my function was inside (comment ) so it was not created
yeah, sorry, #_ doesn't accept invalid forms, it looked like it did due to a corner case nrepl behavior for me locally
that seemed surprising to me :)
haha I saw you almost replying before, I am glad I got the chance to correct the misinfo
#_ works by reading then discarding so seemed like it still has to read just as much as comment
Hey everyone. Could I please get some guidance on how to organize projects and deploy them to a cloud platform? For a simple scenario, I would like to have a client (re-frame) and server (some REST Api framework) projects. AWS Beanstalk SE platform seems to assume these would be bundled/deployed as one application which isn’t ideal - it would be nice to treat these as components that can be updated separately. Beanstalk Docker adds additional overhead. Any help would be very appreciated. I’m open to other cloud platforms. Thank you!
if you don’t intend to bundle the client and server, how would you like to serve the client resources (html/css/js/etc.)?
I don't exactly know 🙂 This may be part of the question. Beanstalk can serve static files but I don't have it working nor do I know if this is a good way to do it.
if you can serve them as static files, that’s typically the way to go
i’ve only used beanstalk with python. are there clojure oriented docs? otherwise i would follow the java focused docs and deploy as an uberjar
It's https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/java-se-platform.html#java-se-namespaces, and I'm experimenting with uberjar. In Beanstalk, server and client would effectively be bundled/uploaded together (unless I create multiple Applications). Perhaps this would be easier in EC2? Is it more typical to bundle such components in one project? Just trying to understand what the options are and what's more common. Thank you.
if you have two repos, you could create two environments
if they’re in the same repo, then I would just bundle them together unless there’s a compelling reason not to
it kinda depends on how much experience you have with devops
I’ve heard good things about heroku, but I’ve been doing devops for a long time so I prefer something more flexible like beanstalk
for hobby projects, I use digital ocean and just deploy an uberjar. the uberjar also serves the static assets needed on the clientside
it means that my dev and production environments are very similar
the reason I use beanstalk for production is that it provides a deployment process pretty similar to one I would write myself out of the box. it’s fairly flexible and has sane default for auto scaling, rolling deployments, security groups, load balancing, etc.
This is helpful. Thank you.
are you required to run on AWS?
No. This is for personal project(s). Just trying to figure out cloud deployment.
yea, for personal projects, I just use digital ocean and deploy an uberjar. (by deploy, I mean I rsync the jar to the server and then start the server in an emacs daemon).
if you’re open to other options, it may be worth asking the chat what they recommend for deploying personal projects (without narrowing it down to AWS). I seem to recall heroku being one of the easier options to get started with.
I am open to other options, and re-phrased original post slightly. Thanks!
I also found this resource, https://github.com/luminus-framework/luminus/blob/master/resources/md/deployment.md
I'm using clj -m namespace-name to call the -main function from the command line. It seems to not just run -main, but all functions in the namespace? Is there a way to run just -main?
clojure doesn't have a "compile only" mode, unlike many other languages. the solutionis to put everything that shouldn't run on file load into defns, and bind them with let inside main
(or some other more sophisticated variation, but that's the basic one)
clj -m will load the file and evaluate every top level form
then invoke -main
I'm calling a 3rd party library that seem to generate side-effects that I'd like to not execute until I call it in -main. I'm using def instead of defn on the 3rd party lib. I'm not sure how to best go about this
a) don't use def or b) use delay
don't use the lib, or change it to not put side effects in def, there's no other solution without forking the compiler(?)
I think I understand now, thanks @noisesmith and @U064X3EF3!
hello all! I am working with clojure spec. Does anyone know the best way to express s/def for a value that must either be a non blank string or nil? For then non-blank part I have (s/and string? (complement str/blank?))
you could wrap that in (s/nilable ...)
I would do (s/nilable (s/and string? (complement str/blank?))) I think
nilable is optimized to cover the nil case so it's better at the top level
I've come to believe it would probably be useful to have a pred/spec specifically for non-blank strings
given that it's both common and cumbersome
well it wouldn't be that - we can optimize the impl
and the generator
I think the example above should gen
Something like (-> d (get-in [:one :two]) (select-keys [:three :five]))
should work as well.
But my personal favourite is just two get-in with a let, or a let where you get the inner map and then use that to extract three and five using keywords. Simple and readable
there's also (-> d (get-in [:one :two]) ((juxt :three :five)))
though most people hate to see (( inside ->
Clojure, where "there's always many and --preferably even more-- non obvious ways to do it"
if that weren't true, what would we do with all the unused capacity for aesthetic opinions?
too real
Ok thanks for that juxt is going to solve some other stuff for me too, what a useful but non-obvious function, no idea it was there
I find it pleasing, writing a function that has juxt in it is almost like writing a haiku
which is reason to be suspicious of it, of course :D
I'm reminded of that old copypaste which I can't seem to find now, where the beginner haskell programmer uses '1 + 1', the grad student uses a Peano arithmetic implementation, the phd does the Peano calculation in the type checker, and the expert uses '1 + 1'
meanwhile, juxt
is like the first 'functional programming thingy' I ever remember learning, and I just remember thinking 'ok, so this this is it, juxt, map, reduce, monads...', I even implemented it in PHP for some ghetto web 'framework'. And then never used it again
once the checkout is set up, you should be able to reload the library files as you edit them
using the :reload
or :reload-all
arg to require
, or whatever shortcut your editor offers
even without a checkout load-file
will redefine the ns from a file, and the checkout makes sure you see the changes if you restart too
sometimes what I do is insert a deliberate error (like a garbage token at the top of the file) to prove whether the file is loaded from what I'm editing or not
I have some printlns that I am doing to see if the changes took effect but the outputs is still the same
but there are things that would prevent the printlns if they are not at the top level (eg passing a function isntead of var to a long lived process, attempting to redefine a defmulti...)
@mario.cordova.862 what does (io/resource "m_ns/my_file.clj")
return - it will show the actual path that clojure uses when reloading
(that is, the path to your ns, without the containing directories)
eg.
scratch=> ( "clojure/core.clj")
#object[.URL 0x25d61f8d "jar:file:/Users/justin.smith/.m2/repository/org/clojure/clojure/1.10.1/cloju
re-1.10.1.jar!/clojure/core.clj"]
which shows I get clojure via a jar in m2
with a checkout that's set up properly, it should return the path to the file on disk in the original project
The dependency file I want reload is called corefuncs.clj
and its namespace is myns.corefuncs
and when I call (
I get #object[
so your checkout isn't set up
it actually has jar!/...
in the middle there
I know that because the URI is a jar URI
you can't hot reload from the jar, because you didn't change the jar
what the checkout should be doing is setting your classpath so asking for that file gives you a path to the file on disk, and it's not doing that
oh wait, lein now has built in checkouts separate from that plugin...
so the symbolic link should have worked (after just one initial restart)
@mario.cordova.862 one gotcha, the magic dir is checkouts
not checkout
https://github.com/technomancy/leiningen/blob/master/doc/TUTORIAL.md#checkout-dependencies
and you restarted the repl at least once since adding the link in checkouts? if so I can't tell you what the issue might be
another gotcha is that this checkouts scheme only works for other lein projects
> Make sure not to override the `base` profile while using checkouts. In practice that usually means using `lein with-profile +foo run` rather than `lein with-profile foo run`
is it possible to use with-redefs
to wrap a function? that is, can I refer to the original function that is being replaced, from the function I am replacing it with?
Yep, just store a reference to the original function in a let. I would give an example but clojure + phone = not good.
alter-var-root is a thing too
if you refer to a var by name in a function, it's resolved at runtime each time it's used, by using a different name in a let, you "capture" the value at one point in the execution