Fork me on GitHub
#beginners
<
2021-12-13
>
Adam Kalisz00:12:27

Is it possible, to have some side-effecty thing as a binding in a doseq and still doing side effects in the body? Like this:

(doseq [x (range 0 3)
        _ (log/info "LOG" x)
        y ["a" "b" "c"]]
  (spit "test_doseq.txt" [x y] :append true))

noisesmith00:12:30

change _ (log/info ...) to :let [_ (log/info ...)]

šŸ‘ 1
noisesmith00:12:43

the problem is that you aren't consuming _

noisesmith00:12:27

doseq is a big weird macro, it has a lot of counterintuitive corner cases, inevitably

Adam Kalisz00:12:26

Great, it works! Yes, it is perhaps better to just have the other doseq inside the body for readability. Thank you for your time.

Adam Kalisz00:12:09

It seems to only do the first side-effect here. I want to log something only when x is different than the previous one without embedding another doseq in the body just so I can have a log.

sova-soars-the-sora06:12:16

(defn add-submap [m new-key new-keys-value]
  (reduce-kv
   (fn [acc k v]
     (assoc acc k (assoc v new-key new-keys-value)))
   {}
   m))
=> (add-submap {:a {:b 1} :c {:d 2} :e {:f 3}} :email-verified nil) => {:a {:b 1, :email-verified nil}, :c {:d 2, :email-verified nil}, :e {:f 3, :email-verified nil}}

sova-soars-the-sora06:12:33

took me a little while to wrap my head around what was going on, but it was satisfying to figure out! šŸ˜ƒ

leifericf10:12:50

Does anyone know of a good resource (books, talks on YouTube, blog posts, etc.) which provide a high-level overview of best practices and libraries for ā€œfull-stack web developmentā€ using Clojure (back-end) and ClojureScript (front-end)? Iā€™m looking for a resource to give me the ā€œlay of the land,ā€ so to speak. A bit more context: Coming from a background of using ā€œlanguage/framework pairsā€ such as PHP/Laravel, Python/Django, Ruby/Rails and Elixir/Phoenixā€”Iā€™m struggling with the fact that, with Clojure, the recommended approach is to compose various libraries, such as Ring, Compojure, Reitit, Pedestal, Re-agent, Re-frame, Hiccup, Garden, etc. I see there are also some ā€œhigher-level libraries,ā€ such as Luminus and Fulcro. Iā€™m searching for something that will teach me how to choose and compose the ā€œrightā€ libraries, in lieu of a framework. Note that I have already purchased a copy of ā€œhttps://pragprog.com/titles/dswdcloj3/web-development-with-clojure-third-edition/,ā€ which Iā€™m hoping will be a good starting points. From skimming through the table of contents and reviews, it seems to be focused on Luminus. (?) Iā€™m looking forward to working through that book during my upcoming Christmas vacation.

dharrigan10:12:08

Hi! Here is a good resource:

1
dharrigan10:12:17

Also, the parent

dharrigan10:12:47

I've heard good things about too

tschady12:12:08

see #fulcro

Akiz16:12:33

I think this is a good introduction to fullstack clojure webdev https://pragprog.com/titles/dswdcloj3/web-development-with-clojure-third-edition/

1
leifericf17:12:49

Thanks, @UBRV1HXPD! I purchased that book a few weeks ago, and Iā€™m planning to read it over the Christmas holidays.

šŸ‘ 1
sova-soars-the-sora04:12:10

I'm gonna say Compojure with Ring on the backend Rum via Shadowcljs on the frontend mix and match static and js however you need Selmer for templating html

sova-soars-the-sora04:12:37

Pedestal on the backend is also good for routing / middleware (instead of Ring)

leifericf13:12:26

Thanks for the tips, @U3ES97LAC!

V11:12:32

I am trying to more aware of how i setup my functions, and I maybe got to a state where i overthink it waay to much. This is a very basic example, but even here I have doubts: I have a validation function that validates an object in an s3 bucket. This function needs to verify that a virus-scan-status is clean as well as a bunch of other stuff. Let me use the virus scanning as example.

(defn is-virus-scan-clean? [s3-client s3-bucket-name s3-key]
  "Returns true if the virus scan is clean"
  (let [scan-status (get-virus-scan-status! s3-client s3-bucket-name s3-key)]
    (= "CLEAN" scan-status)))

(defn is-virus-scan-clean2? [scan-status]
  (= "CLEAN" scan-status)) 

;; I HAVE LEFT OUT SOME OTHER VALIDATION DETAILS IN THESE FUNCTIONS TO MAKE IT CLEARER
(defn validate-s3-object [s3-client s3-bucket-name s3-key]
    {:virus-clean? (is-virus-scan-clean2? (is-virus-scan-clean? s3-client s3-bucket-name s3-key))})

(defn validate-s3-object2 [s3-client s3-bucket-name s3-key]
  (let [scan-status (get-virus-scan-status! s3-client s3-bucket-name s3-key)]
    {:virus-clean? (is-virus-scan-clean2? scan-status)}))
Here i have 2 functions. Function1 first fetches the relevant scan-status inside the is-virus-scan-clean? function. This i currently find the best, however, it is not very pure. I also find it weird that i parse in a bunch of s3-info stuff to this function. Function2 receives the scan-status as input and therefore the function itself is pure. However it doesn't seem like there is much i gain from this function being pure. However i like that this function does not need any s3-info stuff to perform this action. Maybe there is no correct answer, but i would like to hear what people think about this

walterl12:12:26

I prefer the second approach, since (as you've mentioned) it leads to more pure functions. Also, the first approach violates the single responsibility principle: it fetches the status and checks it.

walterl12:12:07

Style side note: predicate function names are better without is- prefixes.

walterl13:12:42

The benefit of the second, "more pure functions" approach isn't as clear in a tiny example like this, but pure functions are generally easier to reason about and test.

walterl13:12:10

Maximizing for function purity also has the positive side effect of pushing side effects closer to the boundaries of your program, isolating it to some known subset of your code base.

walterl13:12:43

(I forget which book/article I learned that from, but it was a pretty profound realization. In the book/article the author was building up an RDD solution to a problem, continuously refactoring the working code to factor out pure functions. It was beautiful to see it applied and what the results are. wow)

V13:12:31

That makes sense. Sounds very interesting. If you find out the name of the book/article please let me know!

šŸ‘ 1
walterl22:12:01

I think it might have been this talk: https://invidious.snopyta.org/watch?v=vK1DazRK_a0 by Rafal Dittwald

šŸ™Œ 1
walterl22:12:40

It's pretty great either way šŸ™‚

walterl22:12:13

The https://libredd.it/r/programming/comments/bt84iq/solving_problems_the_clojure_way_video/ of that video also has some relevant discussion. The more common phrase "pushing side-effects to the system edges" is used there, as well as "functional core, imperative shell", which is often referenced.

šŸ™Œ 1
V11:12:47

So bascially its a question if its better to group all the sideeffects to wind up in the outer validation function to then go on calling a bunch of pure functions. Or if its better to call the function with sideeffects in the function that needs the result of said sideffect

Jelle Licht11:12:40

Is there a clojure spec (1) way to easily specify N (hardcoded) repeats of something? Or just s/cat and hardcode :entry1, :entry2, :entry3ā€¦?

Jelle Licht11:12:15

As a simple example: how would you spec a tic-tac-toe game field, as a vec of vecs (3x3)?

fearnoeval12:12:23

spec/coll-of has :count and :kind parameters, which I think would get you what you're looking for.

Jelle Licht13:12:57

picard-facepalm I can't believe I missed that. Thanks!

šŸ‘ 1
Jelle Licht13:12:28

Another spec question: is there an spec for an interposed string? E.g. conforming ā€œhello,hello,hello,helloā€ with as relevant elements the string ā€helloā€ and character \,

ChillPillzKillzBillz13:12:24

regular expression will be my 2 bits of suggestion...

Jelle Licht13:12:57

Fair enough. I was hoping to be able to compose specs here, as instead of ā€helloā€ I might have stricter requirements on my repeating element.

Alex Miller (Clojure team)13:12:10

Nothing built in for that

Swapneil18:12:15

It technically still uses regex, but you could use the string library's split method with separator #"hello" and then validate the remaining strings via spec/coll-of.

popeye14:12:47

What is the difference between on-change and value here ?

(defn page [ratom]
  [:div
    [:p
      "Please enter your name: "
      [:input {;:on-change #(swap! ratom %)
               :on-change (fn [evt]
                             (reset! ratom (-> evt .-target .-value)))
               :value @ratom}]]
    [:p "Your name is " @ratom]])

pavlosmelissinos14:12:57

value is what the contents of the input field will be when that part of the page is rendered. on-change describes an event that is fired when you edit the contents of the input field (sort of) This has nothing to do with clojure or clojurescript btw. https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-value https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onchange

popeye14:12:49

ohh! got it thanks

Stuart18:12:17

Is their a way to set in my REPL max recursion depth ?

zerjens18:12:24

Are you using recur ? That affects the recursion depth.

Stuart18:12:23

I am, but my code has a problem I can't find that means I'm not terminating the recursion properly so it goes on forever, was hoping to set it to a low number so instead of going on forever it just stops after n recurs

pavlosmelissinos18:12:47

what's your editor? nevermind, I misread the question

Stuart18:12:08

VS Code and Calva

Stuart18:12:37

I know there is INteruppt running evaluation, but for reasons I dont understand sometimes it doesnt stop and I have to kill the repl altogether

Stuart18:12:11

I think because maybe I'm using 100% CPU

zerjens18:12:22

@U11BV7MTKā€™s answer in using:

extra parameter (often called "gas")

šŸ‘ 1
zerjens18:12:57

e.g.

(loop [my-counter 0
       [h & t]    some-list]
  (if (= my-counter 10)
     "DONE"
      (recur (int my-counter) t)))

noisesmith19:12:58

funny enough, int is obviously a typo but would not error :D

noisesmith19:12:08

(it would just quietly do the wrong thing)

šŸ˜‚ 2
zerjens20:12:24

hey there stranger! been a while since Iā€™ve had a code review from ya

šŸ˜† 1
dpsutton18:12:24

Are you trying to increase that limit or lower it? From some quick reading, it looks like the jvm doesnā€™t expose this directly, but you can influence it by setting the stack size for the jvm

Stuart18:12:43

I'm using recur, but I'm debugging an issue in my code where i'm not terminating the recursion as I think I am. So it goes on forever, and sometimes I'm having to kill the repl. I was just wondering if I could maybe set it to 20-30 or something

dpsutton18:12:46

ah. i was assuming actual calling the function style recursion rather than looping. In this case you are in complete control of the control flow. Add an extra parameter (often called ā€œgasā€) and throw an error when it is above some threshold

āœ… 1
Stuart18:12:35

ah ok, i guess i could do something like

(loop [stuff, more stuff, x]
   (if (= x 10)
     :stop
   (recur ojdfp djsdo (inc x))
Thanks

Stuart18:12:32

I'm happy that I'm not the only person who has this issue!

noisesmith20:12:22

another good trick is (when (zero? (mod x 100)) (println ....))

noisesmith20:12:35

just to figure out why it isn't stopping

āœ… 2
dgr21:12:16

I typically use CIDERā€™s debugger so I can inspect variables and see how they are evolving. Thatā€™s the quickest way to figure out a runaway recursion in my experience. But that might not be part of the beginner class.