Fork me on GitHub
#beginners
<
2021-11-22
>
sova-soars-the-sora05:11:06

any recommendations on books for programming systems with many simultaneous threads?

Cora (she/her)05:11:58

I've been told that Java Concurrency in Practice is good

Cora (she/her)05:11:33

it's quite old at this point, though

sova-soars-the-sora05:11:08

What's Java? Is that some sort of drink ? 😋

sova-soars-the-sora05:11:11

I see lots of "Update your book dude!" lol

sova-soars-the-sora05:11:38

sleeps justice 🌃

sova-soars-the-sora05:11:26

I am wondering more about real-time systems with lots of users

respatialized22:11:27

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.

sova-soars-the-sora05:11:55

I suppose that describes the internet. compose

shidima12:11:53

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

Max Deineko12:11:13

Might your input contain (possibly non-printable) characters other than "(" and ")"?

Max Deineko12:11:50

My suggestion would be to check the sequence of values that floor takes on problematic input.

shidima12:11:52

It was indeed some whitespace, I added a str/trim and it works as expected

✔️ 1
tbrooke13:11:09

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 ()*;

popeye15:11:11

I am integrating aws redis cache in my clojure code, Can anyone help me in this? Any documentation and which library to be used ?

popeye15:11:43

@U02EA2T7FEH is there any sample example where this been integrated ?

Darin Douglass15:11:22

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

Darin Douglass15:11:31

the biggest thing is the connection stuff, which is described in the README

popeye15:11:51

oh ok, Thanks for your help 🙂

popeye18:11:47

@U02EA2T7FEH can we use this library to work with aws redis ?

Darin Douglass18:11:26

yep, it’ll work with elasticache

Darin Douglass18:11:35

i’ve used it as such

popeye19:11:41

@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

popeye19:11:04

Will take a look

cdeszaq15:11:20

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?

Apple16:11:12

move the final binding to body. how about that.

cdeszaq16:11:06

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.

Cora (she/her)16:11:32

you don't want to bind it to anything, though

Cora (she/her)16:11:45

which already breaks it out of the let binding format

cdeszaq16:11:57

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.

Cora (she/her)16:11:33

you can always put the binding in the body 😉

cdeszaq16:11:02

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)

Cora (she/her)16:11:13

that's exactly what I mean

Cora (she/her)16:11:37

sorry, I meant "put the bound variable in the body"

👍 1
Cora (she/her)16:11:53

then it's a short thing in the body that describes what you're returning, I guess

cdeszaq17:11:11

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)]))

pithyless17:11:34

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).

pithyless17:11:49

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.

👍 1
Eddie17:11:11

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.

cdeszaq17:11:03

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))

cdeszaq17:11:52

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")))

pithyless17:11:54

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

pithyless17:11:59

(-> (slurp file)
    (clickable-links)
    (tag-multiline-links "$RET")
    (md/markdown :data :html)
    (join-multiline-links "$RET$"))

pithyless17:11:29

^ probably needs better domain-appropriate names, but some food-for-thought

pithyless17:11:36

(also in this case the function docstrings could serve as a good place for someone to learn more about why the operation exists)

cdeszaq17:11:31

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?

pithyless17:11:25

I find it reassuring that let has a final return value that is not dependent on the order of bindings :)

pithyless17:11:50

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

Cora (she/her)17:11:50

you could always.... write a macro

cdeszaq17:11:45

🙂 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.

Cora (she/her)17:11:07

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

cdeszaq17:11:12

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.

Cora (she/her)18:11:53

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

pithyless17:11:20

(defmacro goto ,,,) ducks

👀 2
respatialized23:11:35

defmacro, the penultimate GOTO

Ben Sless06:11:52

So just a cps transform?

CarnunMP22:11:14

Let's say I evaluate the following in my editor, via cider-nrepl (and vim-fireplace). What happens to the prns? How do I capture them? :thinking_face:

(future
  (loop [i 0]
    (Thread/sleep 1000)
    (when (< i 10)
      (prn "yo")
      (recur (inc i)))))

hiredman23:11:53

it is kind of complicated, but usually I would expect them to go to the same place the repl prompt is printed

hiredman23:11:08

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

hiredman23:11:33

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

CarnunMP23:11:01

Hmm yeah. Not getting anything where the repl prompt is printed—or in vim. :/

hiredman23:11:12

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

hiredman23:11:22

there is a #vim, that might a good place to ask any specific questions

👍 1
CarnunMP23:11:23

Maybe the thing to do is force it to where the repl prompt is printed, then. I'll give that a go...

CarnunMP23:11:27

Thanks. :))