Fork me on GitHub
#clojure
<
2022-05-23
>
Yogesvara Das12:05:09

Is there something like partition that yields remaining elements if the don't fit the partition size? Found it partition-all

Yogesvara Das12:05:53

just found it there myself too 😅 thank you

👍 1
R.A. Porter12:05:14

Or, partition with the optional pad. From the docs: > If a pad collection is supplied, use its elements as necessary to complete last partition upto n items

andersmurphy13:05:42

What’s the transducer equivalent of run! If you just want to do a side effect at the end of the transducer?

jjttjj13:05:53

transduce will run through the entire sequence passed to it so that should work

andersmurphy13:05:07

Thanks, I’ll give that a go.

mpenet13:05:48

run! + eduction comes to mind

mpenet13:05:14

depends on what you need to do, it's not entirely clear

andersmurphy13:05:54

ahhh that’s a good shout. I’ve hit a paginated api using iteration and just want to log each item after doing some transforms.

ghadi13:05:15

I'd be interested in your usage of iteration, if you feel like sharing it

andersmurphy13:05:42

(->> (iteration
        (partial get-discord-guild-members! external-id)
        :kf    #(-> % last :user :id)
        :initk "0"
        :somef seq)
       (eduction cat (remove (comp :bot :user)))
       (run! update-member))

andersmurphy13:05:37

First time using iteration . Seems to capture the semantics of pagination quite well.

andersmurphy13:05:48

discords api doesn’t return the last item id at the top level of the response, so you have to dive in and find it yourself by getting the last item. The only thing is that I’d probably always want to cat the results, feels like I’d expect that to be a part of the iteration api. But, other than that minor quirk (and I’m sure there’s a good reason for it) it’s much nicer than having to roll you’re own mechanism every time you deal with a third party api that’s paginated. @U050ECB92

ghadi14:05:41

good feedback. catting is left out because not all iterations will need it

ghadi14:05:09

(sometimes you'll want the page response, and not just the contents)

ghadi14:05:58

if you're using https://discord.com/developers/docs/resources/guild#list-guild-members it looks like :initk can be nil as the api param says the default is already '0'

ghadi14:05:34

if get-discord-guild-members! returns a vec or nil, then you can also kill the somef

ghadi14:05:21

(iteration (fn [uid] ...) :kf #(-> % peek :user :id))

andersmurphy14:05:22

ahh nice, currently it’s an empty vec, but I can move seq to that function then it make iteration even simpler to use. Have to say clojure getting functions for handling these core/common sorts of system abstractions is really nice.

andersmurphy14:05:33

#(-> % peek :user :id) does peek work here? As it’s the id of the last item that I’d want to pass up to discord.

ghadi14:05:42

only if it's a vector

andersmurphy14:05:05

Ahh of course!

ghadi14:05:06

(peek [1 2 3])
=> 3

ghadi14:05:13

last is O(n)

andersmurphy14:05:24

yeah I had some concerns with last

ghadi14:05:29

you almost never want last, except inside a macro

🙏 1
andersmurphy14:05:56

Completely forgot peek depends on the underlying collection.

Yogesvara Das14:05:31

What's the idiomatic way to run the same pieces of code over and over again until it does not raise an exception?

borkdude14:05:40

Use Erlang (kidding ;))

😄 4
ghadi14:05:37

@yogdas my general tactic is to make a generic retry helper

🙌 1
borkdude14:05:38

You can probably just use loop

ghadi14:05:49

you need a function to invoke (an 'op'/thunk)

ghadi14:05:55

a predicate to know whether you need to retry

ghadi14:05:40

and a strategy to backoff -- I usually make a fn of a retry "epoch", that returns either a number of millis to sleep before the next retry, or nil, indicating cessation

ghadi14:05:07

(defn retry [op retry? backoff]
  (loop [epoch 1]
    (let [ret (op)]
      (if-let [ms (and (retry? ret) (backoff epoch))]
        (do (Thread/sleep ms)
            (recur (inc epoch)))
        ret))))
something like this

ghadi14:05:21

you'll need to catch the exception around op or within op

ghadi14:05:48

you can tinker with parameterizing things

Yogesvara Das14:05:08

hmm I was going to just do while (= ::failed (try ...

ghadi14:05:24

backoff is easy as passing in (fn [epoch] (* epoch 200))

ghadi14:05:50

you can do jitter, or capped retries, etc.

potetm14:05:32

Passing fns is a really good (and underused) strat for this use case.

potetm14:05:45

(I wouldn’t use fusebox directly. I’m not doing anything with it. But you can feel free to rip whatever code you want out of there.)

Yogesvara Das14:05:14

Thank you all.

erwinrooijakkers15:05:32

Is it possible to destructure strings with a slash using strs?

erwinrooijakkers15:05:57

(let [{:strs [foo/bar]} {"foo/bar" "quz"}] foo/bar) > foo/bar - failed: simple-symbol? at: [:bindings :form :map-destructure :strs] spec: :clojure.core.specs.alpha/strs > {:strs [foo/bar]} - failed: simple-symbol? at: [:bindings :form :local-symbol] spec: :clojure.core.specs.alpha/local-name > {:strs [foo/bar]} - failed: vector? at: [:bindings :form :seq-destructure] spec: :clojure.core.specs.alpha/seq-binding-form

ghadi15:05:02

no. strings are opaque, unlike keywords which have a namespace

👍 2
simongray09:05:59

@U2PGHFU5U Although he could write

(let [{:keys [foo/bar]} (update-keys {"foo/bar" "quz"} keyword)]
  bar)