This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-11-22
Channels
- # announcements (39)
- # architecture (9)
- # aws (2)
- # babashka (17)
- # beginners (73)
- # calva (6)
- # cider (27)
- # clj-kondo (140)
- # cljdoc (67)
- # cljsrn (1)
- # clojure (99)
- # clojure-dev (4)
- # clojure-europe (35)
- # clojure-nl (7)
- # clojure-spec (19)
- # clojure-uk (2)
- # clojurescript (40)
- # community-development (3)
- # cursive (10)
- # datalevin (2)
- # datavis (2)
- # datomic (27)
- # deps-new (5)
- # events (2)
- # fulcro (38)
- # integrant (6)
- # jobs (3)
- # keyboards (1)
- # leiningen (13)
- # lsp (3)
- # malli (10)
- # meander (5)
- # membrane (1)
- # membrane-term (9)
- # missionary (3)
- # off-topic (29)
- # polylith (3)
- # reagent (3)
- # reitit (5)
- # remote-jobs (2)
- # reveal (7)
- # shadow-cljs (20)
- # tools-build (4)
- # tools-deps (8)
- # vim (10)
- # xtdb (3)
any recommendations on books for programming systems with many simultaneous threads?
I've been told that Java Concurrency in Practice is good
it's quite old at this point, though
What's Java? Is that some sort of drink ? 😋
https://stackoverflow.com/a/10214606 from the author
I see lots of "Update your book dude!" lol
sleeps justice 🌃
I am wondering more about real-time systems with lots of users
the cheeky recommendation that Alan Kay gives for designers of distributed systems is https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4691023/, a textbook so massive that it is sold in looseleaf so readers can bind it themselves into separate binders. his argument for it is that the only systems in nature that have successfully scaled to billions of components are biological systems, so we need to learn from them.
I suppose that describes the internet.
My code is off by one, and I cant figure out why: https://github.com/christiaan-janssen/advent2015/blob/master/src/day_01.clj The correct awnser is 74, but I get 73
Might your input contain (possibly non-printable) characters other than "(" and ")"?
My suggestion would be to check the sequence of values that floor takes on problematic input.
I am new to Clojurescript and more particularly javascript interop: I am using straight Clojurescript and I want to be able to call the following parse and and getData() functions from my CLojuerscript - I can’t figure out how to even begin and I can’t find a good tutorial or reference:
The code is below - I have to create objects and deal with a promise:
const template = await Template.fromDirectory('./test/data/latedeliveryandpenalty') ;
// load the DSL text for the template
const testLatePenaltyInput = fs.readFileSync (path.resolve(__dirname, 'text/', 'sample.md'), 'utf8') ;
const clause = new Clause (template) ;
clause.*parse* (testLatePenaltyInput) ;
// get the JSON object created from the parse
const data = clause.*getData ()*;
I am integrating aws redis cache in my clojure code, Can anyone help me in this? Any documentation and which library to be used ?
https://github.com/ptaoussanis/carmine is the library i’ve always used
@U02EA2T7FEH is there any sample example where this been integrated ?
the readme is pretty thorough. the carmine api matches the redis commands, so carmine/get
== redis GET
, etc so if you know what you want to do in redis, translating into carmine code is pretty simple
the biggest thing is the connection stuff, which is described in the README
i use http://grep.app to search for examples. https://grep.app/search?q=taoensso.carmine%20%3Aas
I used this library once. https://github.com/lerouxrgd/celtuce
@U02EA2T7FEH can we use this library to work with aws redis ?
yep, it’ll work with elasticache
i’ve used it as such
@U02EA2T7FEH.. I never configured aws earlier... Sorry to ask such questions.. but how it is configured in clojure? I see python example https://github.com/aws-samples/amazon-elasticache-samples/blob/f12935d1f3427a3958550749e38e62f039d6f619/database-caching/example.py#L42
here’s the full connection spec that i’d suggest using https://github.com/ptaoussanis/carmine/blob/master/src/taoensso/carmine.clj#L31
Is there a flavor of let
which will return the final binding if there is no body? If the bindings are just a data pipeline ->>
does a great job, but let
is often seen with the only body expression simply being the terminal binding which feels like it breaks the flow in what seems to be a very common case. Or perhaps I’m thinking about things the wrong way?
Yes, that occurred to me, and is better than simple repetition, but it also breaks out of the structure of the let
binding block for no reason other than syntax constraints. I realize it is a small thing, and perhaps my aesthetic sense is overly tuned to appreciate consistency/regularity, but I want the clean lines of a single block while also having my imperative cake.
you don't want to bind it to anything, though
which already breaks it out of the let binding format
The binding as a label is often useful, though you could argue that’s what the function name should be doing. But your point of “you don’t want to use the binding so why bind” is a good one I think.
you can always put the binding in the body 😉
This confuses me slightly… Please excuse the trivial / useless example, but if this is the case I’m struggling with, how would “put the binding in the body” look?
(let [x 1]
x)
that's exactly what I mean
then it's a short thing in the body that describes what you're returning, I guess
Here’s a more concrete example and some options, 2 of which are options today and the bottom 2 are examples of what is in my head:
(defn repeat-last-binding [input]
(let [a (foo input)
c (bar b)
d (baz b)
output (quux c d)]
output))
(defn body-is-last-bound-expression [input]
(let [b (foo input)
c (bar b)
d (baz b)]
(quux c d)))
(defn labeled-output [input]
(let [b (foo input)
c (bar b)
d (baz b)
output (quux c d)]))
(defn ignored-binding [input]
(let [b (foo input)
c (bar b)
d (baz b)
_ (quux c d)]))
Remember also that the name of the function serves as a name for the last binding (assuming the function is well named and doesn't try to do too much).
And then whether you use version 1 or version 2 depends on whether the last binding output
is obvious from and repeating the name of the function, or not.
In my opinion, using the symbol output
and _
is a hint that the final binding isn’t adding much clarity or value. Perhaps that is just because this is an example and your real use case uses a more informative name. In that case, I would consider using a comment rather than a binding.
Yes, this is a contrived example, which has other issues as well. eg. the binding symbols are all the same length, enhancing the “tabular” shape of the binding block, when in reality this wouldn’t hold and so the effect would be much less. This is the actual code, from a blog article, which put the question into my head and pointed out the aesthetic problem I’ve been bouncing off of in my own code:
(defn markdown->html [file]
(let [markdown (slurp file)
;; make links without markup clickable
markdown (str/replace markdown #"http[A-Za-z0-9/:.=#?_-]+([\s])"
(fn [[match ws]]
(format "[%s](%s)%s"
(str/trim match)
(str/trim match)
ws)))
;; allow links with markup over multiple lines
markdown (str/replace markdown #"\[[^\]]+\n"
(fn [match]
(str/replace match "\n" "$RET$")))
html (md/markdown markdown :data :html)
html (str/replace html "$RET$" "\n")]
html))
The linear nature here is amenable to just using the thread-first macro, so is also not a perfect example, but the thread macros’ “return the last thing” semantics seem to align well with my sense of aesthetics, since all steps are “at the same level”.
(defn markdown->html [file]
(-> (slurp file)
;; make links without markup clickable
(str/replace #"http[A-Za-z0-9/:.=#?_-]+([\s])"
(fn [[match ws]]
(format "[%s](%s)%s"
(str/trim match)
(str/trim match)
ws)))
;; allow links with markup over multiple lines
(str/replace #"\[[^\]]+\n"
(fn [match]
(str/replace match "\n" "$RET$")))
(md/markdown :data :html)
(str/replace "$RET$" "\n")))
You have no let
in this example, but if I understand correctly that those comments could serve the same purpose as let bindings (for documentation purposes), I'd argue that those comments and implementation could be replaced by a better-named function
(-> (slurp file)
(clickable-links)
(tag-multiline-links "$RET")
(md/markdown :data :html)
(join-multiline-links "$RET$"))
(also in this case the function docstrings could serve as a good place for someone to learn more about why the operation exists)
Yes, the linear nature of that computation makes the thread macro an obvious choice. But what about non-linear computation flows, where there are sub-computations which need to be re-used later? let
makes that possible by giving a name to each step and making all previous steps available “down the line”, but the tradeoff is that the final step which would get returned has to be “special” and outside the aesthetic flow of the rest of the computation steps. Perhaps this is just the tradeoff for the flexibility let
bindings allow for, or that I should use some other sort of dag-computation
macro which is just a series of bindings and a terminal computation which is returned?
I find it reassuring that let
has a final return value that is not dependent on the order of bindings :)
BTW, https://github.com/Engelberg/better-cond macro can be used as an optional set of let
bindings with an implicit final return. Or the <<-
macro I mentioned yesterday: https://twitter.com/cgrand/status/1281527501387440128
you could always.... write a macro
🙂 The thought occurred to me, but it seems like either someone’s already done it, the standard lib already has it, or it is a sufficiently bad idea that I shouldn’t do so and should instead adjust my thinking.
it really seems like it doesn't add much value, to me, and it would be surprising to find a let
that worked in this way, imo
Yes, the amount of value add is, admittedly, very small, but it struck me as a “mental snag” when moving from clean thread-macro-based functions to let
-based functions that are structured the same way but with computation logic / steps that were not entirely linear.
it's semantically cleaner to not return the final let binding, imo, even if things align visually. they're expressed differently and that indicates to me that they are doing different things
defmacro
, the penultimate GOTO
Let's say I evaluate the following in my editor, via cider-nrepl (and vim-fireplace). What happens to the prn
s? How do I capture them? :thinking_face:
(future
(loop [i 0]
(Thread/sleep 1000)
(when (< i 10)
(prn "yo")
(recur (inc i)))))
it is kind of complicated, but usually I would expect them to go to the same place the repl prompt is printed
prn prints to *out*
which is by default stdout, nrepl will dynamically bind *out*
to something that prints at the repl, and future will copy any dynamic bindings on the thread where it is created to the thread where it runs
if, for example, instead of using future you use something else to launch another thread, and the dynamic bindings are not copied, then it will print to the root/default binding of *out*
which is the same as java's System/out
the output is going to come back asynchronously, and I haven't used vim fireplace or whatever, but my understanding is, at least at one time, that kind of asynchronous output was tricky to handle in vim