Fork me on GitHub
#beginners
<
2021-04-02
>
cschep00:04:33

I’m not sure how exactly to ask this question but the gist is that I have a program that is a loop, that is a chat bot, so it sits and loops and listens to input and responds, pretty starightforward. Doing REPL driven development on it has been challenging because when I run the listening loop it hangs the REPL

cschep00:04:42

is there a way to async that loop in the “background”

cschep00:04:51

and then i can poke and and update a function it calls

cschep00:04:01

to have a more interactive experience?

noisesmith18:04:24

one option to consider is that the bot and the repl can listen to different file descriptors, either because you have multiple connections to one repl process, or you use a dedicated pipe/fifo - a question of making an alternate binding for *in* connected to a different tty

noisesmith18:04:52

(a process with multiple repl connections already makes multiple *in* bindings for you)

dpsutton00:04:22

generally a loop will call some function with some kind of message and then recur. from the repl you would want to not start the loop but just call the function that handles the message

dpsutton00:04:12

kind of a "functional core, imperative shell" type thing. top level you have a loop which takes a message from a socket/web endpoint/queue/what have you and then does actions based on it, and then back to the top of the loop

cschep00:04:07

i’d love to be able to poke at it while it’s running the loop and getting stuff from the server

cschep00:04:14

in that case i’d be passing my own messages in yeah?

cschep00:04:07

i think it’s waiting on a channel for input

cschep00:04:08

(a/<!! event-ch)

cschep00:04:23

in go i would call this as a go routine

cschep00:04:27

and it wouldn’t block anything while it did its thing

cschep00:04:02

core async has go routines? woah

zackteo07:04:28

Hi is there an iterate that allows for side effects?

zackteo07:04:29

am I looking for doseq?

zackteo07:04:28

I want to do something like

(take-while #(>= number-of-weeks %)
            (iterate
              (partial + (rand-nth days-store1)) (rand-nth days-store1)))

hindol08:04:08

Did you try repeatedly?

zackteo08:04:12

whoops I did not. But I'm not sure how I might want to form the sequence with repeatedly

hindol08:04:15

(take 10 (repeatedly #(rand-nth [1 2 3 4 5]))) => (2 5 3 1 2 5 3 5 3 2)

zackteo08:04:24

Yeap I got that part 🙂 but how might i sum it up with the earlier element

zackteo08:04:00

so if the random seq produced is [1 2 3 4 5] I want [1 3 6 10 15

zackteo08:04:33

I want to take-while the last number in the seq is under 1280

hindol08:04:05

(take 10 (map + (repeatedly #(rand-nth [1 2 3 4 5])) (repeatedly #(rand-nth [1 2 3 4 5]))))

zackteo08:04:44

hmmm thanks for all your help but map doesn't take the earlier element :thinking_face:

zackteo08:04:30

I want something like [1 5 7 10 14 19 22 26 .....]

zackteo08:04:38

maybe reductions

zackteo08:04:54

cool I got it 😄

zackteo08:04:38

(take-while #(>= number-of-weeks %) (reductions +
                                                (repeatedly #(rand-nth [1 2 3 4 5]))))

zackteo08:04:48

Thanks @UJRDALZA5 for your help 😄

zackteo08:04:21

no I still can't use take-while

zackteo08:04:07

Is there a way I can do (take-while #(>= 1280 %) (reductions + (repeatedly #(rand-nth [1 2 3 4 5])))) but still have rand-nth do its side effect with each iteration? Like is there another something else I can use instead of take-while

hindol08:04:43

Okay, now I finally understood what you mean by [1 3 6 10 15], 😅

zackteo08:04:14

Sorry if I wasn't too clear 😅

hindol08:04:13

The technical term is cumulative sums. reductions is definitely the right way. I don't understand what you mean by side effect of rand-nth?

zackteo08:04:24

Currently. The take-while will only evaluate the rand-nth once. Meaning if the evaluation is 3 it will always increment by 3

zackteo08:04:01

Whoops yeap am familiar with cumulative sum but didn't think of using that to describe what I wanted whoops

hindol09:04:59

(take-while #(>= 1280 %)
            (reductions +
                        (repeatedly #(let [n (rand-nth [1 2 3 4 5])]
                                       (println "Rand:" n)
                                       n))))
I still don't get it. It seems rand-nth is called every time.
Rand:  3
Rand:  3
Rand:  5
Rand:  5
Rand:  1
Rand:  1
Rand:  1
Rand:  5

hindol09:04:12

Sorry, I shared the link to cumulative sum thinking you might not know the term. But if you already know it, great.

raspasov09:04:38

(run!
  (fn [x] 
    ;TODO do side effect
    (println x))
  (take-while
    #(>= 1280 %)
    (reductions + (repeatedly #(rand-nth [1 2 3 4 5])))))

zackteo09:04:49

The rand-nth is the part that needs the side effect. Let me try...

raspasov09:04:21

Why does rand-nth need side effect? Perhaps you mean that you need the value that rand-nth produces to be used in a side-effect?

raspasov09:04:25

(reduce
  (fn [accum item]
    ;item is the output of rand-nth
    ;TODO side effect here
    (println item)
    
    (if (<= 1280 accum)
      ;stop reducing
      (reduced accum)
      ;else, reduce further
      (+ accum item)))
  ;initial value of accum
  0
  ;infinite lazy seq
  (repeatedly #(rand-nth [1 2 3 4 5])))

raspasov09:04:03

If you want to do side effects, reduce is a good choice

zackteo15:04:09

@U050KSS8M no, I meant that if I use rand-nth only evaluates once. But I want it to reevaluate each time it is called in the seq

raspasov15:04:42

I believe you’re mistaken. Look at the doc string for repeatedly :

Takes a function of no args, presumably with side effects, and
returns an infinite (or length n if supplied) lazy sequence of calls
to it

raspasov15:04:20

If you run the code I pasted, you’ll see ‘item’ being printed many times. It’s different each time.

raspasov15:04:32

Also, the total sum at the end is different each time, which also shows that rand-nth is being called many times.

zackteo01:04:23

@U050KSS8M wow thanks! I'm not sure what I was seeing to think the value of rand-nth wasn't changing. But it actually was. Thanks for your help!!

👍 3
zackteo01:04:46

I think I was mistakenly still thinking about

(take-while #(>= number-of-weeks %)
            (iterate
              (partial + (rand-nth days-store1)) (rand-nth days-store1)))
which had issues cause of iterate

hindol04:04:54

The issue was not iterate, it was partial. partial will only evaluate its arguments once.

(take 10 (repeatedly (partial + (rand-nth (range 10))))) => (8 8 8 8 8 8 8 8 8 8)

hindol04:04:32

If you had an anonymous function instead, it would have worked.

(take 10 (repeatedly #(+ (rand-nth (range 10))))) => (9 9 6 7 3 2 7 4 8 6)

zackteo05:04:25

Wow! Okay okay I'll try to remember that!

zackteo08:04:53

^ this runs but the result used for rand-nth is fixed

zackteo08:04:54

Is there a function or a better way to do what I want.? Am trying to create a simulation of when a factory will refill its stock. So (def days-store1 [2 3 3 4 4 5 5 6]) is saying after there is a 1/8 chance that after 2 days, there is a need to restock. And then it undergoes a renewal process. So it any of those number of days in days-store1 are equally likely again

zackteo08:04:07

Is there a way I can do (take-while #(>= 1280 %) (reductions + (repeatedly #(rand-nth [1 2 3 4 5])))) but still have rand-nth do its side effect with each iteration? Like is there another something else I can use instead of take-while

oxalorg (Mitesh)12:04:58

Hey all! I'm going to be recording a screen cast about how to setup a Clojure + ClojureScript setup from SCRATCH! I struggled quite a bit when starting out trying to create a full-stack project without using templates. So hopefully this would help someone! I'm planning on starting with a blank directory and then walking through each of the following (in order): • deps.edn and REPL Driven Development • Ring + Jetty backend server • JSON api handler + HTML page handler • Hiccup and rendering html • CSS files • Simple vanilla clojurescript example (no additional tools) • Auto building cljs->js (no additiona tools, except cljs itself) • Solving server startup with `dev/user.clj` • REPL jacking in with dev profile • Easier server lifecycle management (basic introduction to the reloaded flow) • Adding in shadow-cljs and jacking in with clj&cljs BOTH • Adding Reagent and fetching our API from frontend • Adding Integrant • Small quick notes on repl_sessions and easy deployment What do you think would be some other important points to cover? or any other suggestions?

👍 15
👏 3
Endre Bakken Stovner14:04:29

What about re-frame? It is on the very top of the stack though.

✔️ 3
sova-soars-the-sora14:04:16

I like using Selmer for html templates so you can pass in variables and invoke them in the html template {{like-so}} I also like using rum a lot for cljs development, and it can actually render html on the serverside faster than hiccup if i recall correctly. Nice list. I think the goal ought to be to get to a repl as fast as possible and after each big step.

💯 3
🙌 3
oxalorg (Mitesh)16:04:35

> What about re-frame? It is on the very top of the stack though. I plan to cover reagent, reframe, and building entire dashboards / admin panels / and complex real world projects with clojurescript. But those are for a separate video and I've been a bit lazy haha. I do have an intro to reagent video up with a simple todo app if you're interested in checking it out: https://www.youtube.com/watch?v=tRYreGS53Z4 🙂

👍 3
oxalorg (Mitesh)16:04:16

> I like using Selmer for html templates I'm a bit on the opposite end here 🙈. After using html templating systems like Selmer over the years, I've come to really appreciate the hiccup approach (and to some extent even jsx). Composing html using clojure functions makes html painfree and powerful! But maybe selmer does make more sense to someone new :thinking_face:

oxalorg (Mitesh)16:04:00

> Nice list.  I think the goal ought to be to get to a repl as fast as possible and after each big step. Yes EXACTLY!! 💯 REPL driven development makes everything so much more lively, I definitely want to give a feel of how to use the clj+cljs REPLs together.

blak3mill3r21:04:48

This is great! I'd love to see figwheel-main in there as well

😊 3
oxalorg (Mitesh)06:04:44

Thanks Blake 🙂 To be honest I haven't really used figwheel-* in any serious capacity, and I feel like shadow solves all my problems especially with it's easier npm integration. I've gone through the figwheel-main docs but I wasn't convinced to give it a try. Do you have any reasons when would one prefer figwheel over shadow or what problems it solves better?

blak3mill3r01:04:09

cider seems to work better with figwheel than with shadow-cljs (although I am not an expert on the latter, perhaps I was doing it wrong)

blak3mill3r01:04:21

like, all the nice cider features were missing

3
oxalorg (Mitesh)06:04:43

Oh! Could you perhaps mention a few features you're missing with cider & shadow-cljs? I haven't noticed anything in particular and found that after a bit of middle ware setup it works perfectly!

blak3mill3r13:04:59

the one I specifically remember missing (with a cider cljs repl) was cider-inspector

blak3mill3r13:04:49

cider-enlighten I think was another

blak3mill3r13:04:56

also completions weren't working for me

oxalorg (Mitesh)17:04:04

Yup, inspect and enlighten don't work for me either, but I rarely use them! Completions do work fine me though :thinking_face:

blak3mill3r23:04:57

good to know... I'll fool around with the emacs side next time and get completions working. Thanks!

bananadance 3
Dimitar Uzunov12:04:08

making a jar file for deployment

💯 6
oxalorg (Mitesh)12:04:04

Thanks yes I could talk quickly about it showing an example. I was trying to stay away from deployment as I wanted to create a separate video on it 🙂

Dimitar Uzunov12:04:09

it is more of a build phase anyway 🙂

👍 3
✔️ 3
Umar Daraz12:04:03

backend and frontend routing may be

💯 3
oxalorg (Mitesh)12:04:40

Thanks. Yes routing is something I want to cover but I'm confused to what depth? I do plan to add a simple (case (:uri request).. router in my jetty handler to explain the flow of how routers work at their core. I mostly tend to use reitit as it's quite nice on both backend and frontend, do you think I should cover those to setup separately? Or are you thinking more along the lines of a single shared router between both frontend and backend?

Umar Daraz13:04:40

I m thinking of separate routing setup for backend and frontend. I don't know that shared routing setup is even possible. If it is possible, would love to see this setup. Im thinking in the lines that, e.g. in nodejs/react app, we mostly add experess and react router at the start. because even a smallish app tend to have few pages on front end and few crud operations on backend.

oxalorg (Mitesh)13:04:52

> I don't know that shared routing setup is even possible. > If it is possible, would love to see this setup. It's definitely possible with reitit, I don't have much experience with it but it would be a great way to learn and document. I would love to do this separately!! Thanks

oxalorg (Mitesh)13:04:35

> Im thinking in the lines that, e.g. in nodejs/react app, we mostly add experess and react router at the start. > because even a smallish app tend to have few pages on front end and few crud operations on backend. Yes that is indeed true, but with adding routers do you think I need to talk a bit about content negotiation/encoding, middlewares or maybe interceptors too? :thinking_face: Edit: Maybe that would be a bit too much haha. I'll think about the most minimal example I can whip up with reitit

Umar Daraz13:04:30

Yeh indeed, negotiation/encoding and middleware come into play. And it may drag the direction to library usage, instead of minimal setup. May be you can have another screen cast, that is more involve with routing after the setup one

🚀 3
💯 3
oxalorg (Mitesh)13:04:06

> May be you can have another screen cast, that is more involve with routing after the setup one Yes looks like that would be best! Thanks for your suggestions and feedback, super appreciate it 😄 ^_^

💯 3
🙏 3
Umar Daraz13:04:50

Here how i setup a minimal reitit example. May be it can be further simplify.

(def app
  (ring/ring-handler
   (ring/router
    ["/api"
     ["/scramble" {:post  scramble-handler}]]
    {:data {:muuntaja m/instance
            :middleware [muuntaja/format-middleware]}})
   (ring/routes
    (ring/create-resource-handler {:path "/"})
    (ring/create-default-handler))))

🙌 3
Umar Daraz13:04:46

thanks @U013MQC5YKD looking forward to the screen cast. cljs

bananadance 3
oxalorg (Mitesh)13:04:48

Lovely! I was thinking something very similar, but I also understand that this can get really daunting for someone quite new 🙈

oxalorg (Mitesh)13:04:26

> looking forward to the screen cast. Thanks haha, I'll be sure to ping you once I have it up 🙂nyantocat

Umar Daraz13:04:06

Yes pls do. I m fairly new in clojure land, And when I was try to setup my project, I was not able to find such screen cast. So I m sure, it will help a lot of new comers

awesome 3
💯 3
🙌 3
oxalorg (Mitesh)13:04:44

I had the exact same experience! Trying my best to fill in this assumed gap, I already have a few beginner friendly clojure videos up here: https://www.youtube.com/channel/UCd588hDu4bszrSHlLXC8eZA If you're interested in checking it out 🙂

Umar Daraz13:04:48

🙌 wow Im sure I will go through each of these videos one by one. thanks of making and sharing, 🎯

bananadance 3
🥳 3
oxalorg (Mitesh)13:04:39

Thanks a lot this means a lot! sharkdance 🙏

Endre Bakken Stovner14:04:41

In the below code the let only differs for the outer loop.

(for [[rulename jobs] (group-by :in-rule jobinfo)
        job jobs
        :let [{:keys [params shell script]} (rules rulename)]]
Still, is the let computed anew for each inner iteration?

Noah Bogart15:04:10

to find out, you could embed a (do (println "hey") (rules rulename))

Noah Bogart15:04:23

but you can also move the :let above the job jobs line

💯 6
Noah Bogart15:04:15

user=> (for [a (range 1 5) :let [b (inc a)] c (range b)] c)
(0 1 0 1 2 0 1 2 3 0 1 2 3 4)

Endre Bakken Stovner05:04:36

Had no idea I could move the let. Thanks!

Adie15:04:14

I have registered cursive with intellij. I now want to run the tests of one of my clojure services. How do I run the tests using cursive?

pavlosmelissinos15:04:11

You've tried the instructions on Cursive's documentation and they don't work for you? https://cursive-ide.com/userguide/testing.html If so, it would help if you could be more specific

zackteo15:04:15

Hi Everyone, how would yall approach a problem of generating a list of numbers that looks like [0 0 2 0 2 0 0 0 2 .... ] where the interval between the 2 are randomly chosen. Perhaps using something like rand-nth [2 2 3 4 5]

hindol16:04:39

(take 100
      (flatten
       (interpose 2 (map #(repeat % 0) (repeatedly #(rand-nth [2 2 3 4 5]))))))
Something like this?

zackteo00:04:48

@UJRDALZA5 Wow yes, this is what I wanted! 😄 Actually my previous question was me trying to take a immediate step to get this

dpsutton15:04:43

i'd probably make a lazy seq that would compute the random interval, put that many 0's and a 2, and then cons onto the "recursive" call

Elliot Stern15:04:50

mapcat seems useful

Elliot Stern16:04:19

(mapcat #(repeat % 0) random-intervals) will generate lists of 0 s of the specified lengths, then concatenate them together. I’ll leave it as an exercise to append the 2 and to generate random-intervals. (edit: replicate -> repeat)

noisesmith18:04:59

btw replicate is deprecated, use repeat

👍 3
dpsutton16:04:44

TIL replicate

hindol16:04:21

Me too. But repeat is favored over replecate.

Alex Miller (Clojure team)16:04:50

replicate is deprecated

oxalorg (Mitesh)16:04:51

Every element in the sequence basically has a random chance of being either a 0 or a 2 (assuming 2's can be adjacent to each other). So something like this should also be enough:

(repeatedly 10 #({0 0 1 2} (rand-int 2)))
;; => (0 2 0 2 0 2 0 0 0 0)

pavlosmelissinos17:04:53

or maybe even (repeatedly 10 #(rand-nth [0 2])) ? this way you have some control over the distribution of the numbers, e.g. you can say (repeatedly 10 #(rand-nth [0 0 2])) if you want to have "twice" as many 0s as 2s (twice doesn't really make sense here, i'm using it figuratively)

Alex Miller (Clojure team)17:04:07

you might also look at test.check generators to make these kinds of things

💡 6
Alex Miller (Clojure team)17:04:33

helpfully, spec makes them for you if you can describe the sequence

Alex Miller (Clojure team)17:04:43

% clj -Sdeps '{:deps {org.clojure/test.check {:mvn/version "0.9.0"}}}'
Clojure 1.10.1
user=> (require '[clojure.spec.alpha :as s] '[clojure.spec.gen.alpha :as gen])
nil
user=> (gen/sample (s/gen (s/+ (s/cat :a (s/* #{0}) :b #{2}))))
((2) (2 2) (2) (0 2 0 0 2 0 0 2 0 2) (0 2 0 2 0 0 0 0 2 0 0 0 0 2) (0 0 0 0 2 0 0 0 0 2 0 0 0 2 0 0 2) (0 0 0 0 0 2 0 2) (0 2 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 2) (0 0 0 0 0 2 0 0 0 0 2 0 0 0 0 0 2 0 0 0 0 0 2 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 2) (0 0 0 0 0 2 0 0 0 0 0 2 0 0 0 0 0 2 0 0 0 0 2))

🤯 6
pavlosmelissinos17:04:53

https://clojure.org/guides/spec#_sequences > * - 0 or more of a predicate/pattern (check out the examples in the docs, they're really helpful)

sova-soars-the-sora17:04:14

Ah, like FSM notation. So + is "one or more" ? thank you i will check out the link

manutter5119:04:44

s/* => “Zero or more instances of” (like in regex)

yiorgos19:04:18

Is there an easy way to parse a date string like this Fri, 02 Apr 2021 18:00:17 GMT into a date instance? I’ve tried with java.time.Instant/parse but didn’t work

henryw37419:04:52

DateTimeFormatter, in java time, will do that if you give it a pattern

👍 3
dpsutton19:04:15

do you know how you ended up with that string?

yiorgos19:04:45

Last-Modified header has a value like that, for example curl -I -X GET

dpsutton19:04:07

oh bummer

((juxt #(get % "Date") #(get % "Last-Modified"))
                              (:headers (http/get "")))
["Fri, 02 Apr 2021 19:49:39 GMT" "Fri, 02 Apr 2021 18:00:17 GMT"]
was hoping those wouldn't be strings like that programatically.

yiorgos20:04:20

in case someone else finds it useful, the way I achieved that:

(def t (.parse java.time.format.DateTimeFormatter/RFC_1123_DATE_TIME "Fri, 02 Apr 2021 18:00:17 GMT"))
(java.time.Instant/from t)

jumar04:04:35

There's also an utility function in ring for parsing HTTP-header style dates:

(ring.util.time/parse-date "Fri, 02 Apr 2021 18:00:17 GMT")
;;=> #inst "2021-04-02T18:00:17.000-00:00"

🙏 3
Joseph Rollins20:04:18

maybe more of a spacemacs question... I have both the clojure layer and lsp layer enabled and when I open a new file I get the namespace autogenerated twice e.g.:

(ns my-ns)

(ns my-ns)
anyone know how I can disable 1 of these two from filling in the namespace?

ericdallo20:04:15

Check *Conflict with clj-refactor when creating new files* https://emacs-lsp.github.io/lsp-mode/tutorials/clojure-guide/

🙌 3
Joseph Rollins20:04:59

awesome, thanks!

👍 3
zach22:04:01

would anyone know how to include XML CDATA in a hiccup map? I am writing a babashka script that takes an edn file with markdown and turns it into an RSS feed. e.g.

[:item
  [:title "new post"]
  [:link ""]
   [:description (markdown->html "**some stuff**")]]

borkdude22:04:27

@webmaster601 according to the readme of clojure.data.xml:

[:-cdata "not parsed <stuff"]

zach22:04:31

oh, my gosh, thank you!

zach22:04:50

Also, thank you for babashka. It is incredible!

❤️ 3