Fork me on GitHub
#beginners
<
2021-10-22
>
Ty02:10:41

I need to process a finite vector as a repeating sequence and start at an arbitrary point in the sequence. `(defonce notes [:a :bb :b :c :db :d :eb :e :f :gb :g :ab])` In this case I need to start at an arbitrary spot in the vector and then get the next 24 items where the end of the list would loop back to the beginning (thus why I was thinking a sequence would be ideal).

Ty02:10:49

I went with the following for now: `(defonce notes-seq (cycle notes))` `(map f (take 24 notes-seq))`

Ty02:10:05

Still working out the arbitrary starting point bit xD

phronmophobic02:10:06

`(drop (rand-int (count notes)) notes)`

Ty02:10:11

Perfect! Thanks

hiredman02:10:28

Map notes to numbers, do modular arithmetic, use range, map back to symbolic names

GGfpc10:10:54

Is there a way to short circuit from a let? Let's say I'm doing something like this

``````(let [parsed-data (parse data)
final-result (do-stuff result)])``````
If the parsing doesn't work correctly I want to abort and return a different value, but I don't want to throw an exception. Is there another way to do it?

Fredrik11:10:18

How does your `parse` function signal errors?

Fredrik11:10:39

If it throws an exception, you can wrap it in a `try` block. If it signals error by returning a special value, you can check for that explicitly and then decide the course of action.

Mno11:10:58

yeah has Fredrik says, if it's throwing out an exception you can catch the offending thing with `try`, if it's just returning nil you can use `or` e.g:

``````(let [parsed-data (try (parse data) (catch Exception e "default"))
final-result (do-stuff result)])

;;or

(let [parsed-data (or (parse data) "default")
final-result (do-stuff result)])``````

Mno11:10:13

another core function that might be worth considering is `cond->`

GGfpc11:10:33

it will return a spec error like :

``:clojure.spec.alpha/invalid``
that `or` function might be useful

GGfpc11:10:37

But maybe I wasn't clear. I want to exit from the let if the parse function returns invalid

Mno11:10:19

ohhhhhhhhh ok.. then yeah look at `cond->` and `if-let` maybe?

Fredrik12:10:53

You could try something like

``````(let [parsed-data (parse data)]
(when-not (= parsed-data :clojure.spec.alpha/invalid)
DO-STUFF))``````

emccue14:10:21

if you dont need destructuring you can make a macro for it yourself pretty easily

emccue14:10:55

``````(def early-return ::early-return)

(defmacro early-returnable-let [bindings body]
(loop [form body
[first & rest] bindings]
(if first
(let [[k v] first]
(recur `(let* [~k ~v]
(when (not= early-return ~k)
~body))
rest))
body)))``````

emccue14:10:32

(let [x 10 y 5 z (if (> x y) early-return 6)] (+ x y z))

GGfpc15:10:43

Thanks, I'll give these a try

Jonas Hinrichs11:10:12

Hi, i cant find any good source that explains what i should use instead of :refer :all `(:require [compojure.api.sweet :refer :all]` what would be a good alternative?

Mno11:10:03

purely as a sytlistic choice I will almost always prefer using `:as` ( for example: `[compojure.api.sweet :as sweet]`) and use sweet/whatever-function because it's more clear that it's not being defined in this namespace.

Mno11:10:46

but yeah `:refer all` is rarely a "Good Idea"™️ at least prefer `:refer [specific-function1 specific-function2]`

👍 1
borkdude11:10:13

@jonas.hinrichs `(:require [compojure.api.sweet :as sweet :refer [commonly-used-function]])`

Xiaoyu Zhang16:10:39

Greetings everyone, any one in windows use Cursive and connect to `nREPL` within `WSL` ? It works fine if I'm using VSCode(with remote plugin) connect to `WSL` but ,I have to move to Cursive to be align with teammates. I tried to connect but Cursive always failed to connect .

Xiaoyu Zhang16:10:55

Thank you! John, it solve my problem and save my day ! one more thing to add is that, in the WSL, user need to bind to `0.0.0.0` explicitly, then IntelliJ from windows can connect to WSL

👍 1
Ty19:10:16

Having some trouble with this. I think the error is in the notes-from-intervals function, but I'm not sure how to debug it.

``````(defonce notes [:a :bb :b :c :db :d :eb :e :f :gb :g :ab])

(defonce notes-seq (cycle notes))

(defn notes-start-n [n]
(drop (.indexOf notes n) notes-seq))

(defonce maj7-intervals [0 4 7 11])

; :f [0 4 7 11] => #{ :f :a :c : e }]
(defn notes-from-intervals [n intervals]
(set (map take-nth intervals (notes-start-n n))))

(defonce active-notes (notes-from-intervals :f maj7-intervals))``````

Ty20:10:04

Oh wow, I think take-nth is very different than I thought it was

pavlosmelissinos06:10:09

That doesn't look like idiomatic Clojure. What are you trying to do?

pavlosmelissinos06:10:58

I haven't seen so many defonces in the same ns before 😛 Your inputs might not change for now but they will at some point, right? Try to write functions that do not depend on globals so much. E.g. put all the defonces in a function and be honest about your functions' inputs. If notes-start-n needs to know about notes, make it a parameter. edit: On the phone right now but if I understand what your goal is I could have a go at it when I get back

orpheus20:10:00

How do I expand a list of vectors to use as arguments in fn call? My fn looks something like this:

``````(defn olp->csv->write [accounts]
(with-open [writer (io/writer "olp.csv")]
Where `olp->csv->create-row accounts` returns the list of vectors, each representing a csv row

orpheus20:10:28

When I look on stackoverflow I see solutions using `apply` but I can’t wrap my head around how I’d use that here

Alex Miller (Clojure team)20:10:30

I think the easiest option here is to just use `cons` to slap the headers on the front

Alex Miller (Clojure team)20:10:17

``````(defn olp->csv->write [accounts]
(with-open [writer (io/writer "olp.csv")]
(csv/write-csv writer (cons olp->csv->headers (olp->csv->create-rows accounts)))))``````

orpheus20:10:30

ahh yeah probably. Thank you

Alex Miller (Clojure team)20:10:29

you lose the vector-ness but all you're doing here is sequential iteration so it really doesn't matter

Alex Miller (Clojure team)20:10:27

you could also do things like `(concat [olp->csv->headers] ...)` or `(into [olp->csv->headers] ...)` etc

Alex Miller (Clojure team)20:10:56

for what you're doing though, those are probably worse

orpheus20:10:13

Alex Miller (Clojure team)20:10:21

the first is effectively the same, but harder to say. the second is going to move all the rows into the first coll, which is not worth doing

orpheus20:10:45

Gotchya. Thank you. So is it uncommon to run into situations where you’d need want to spread a collection?

Alex Miller (Clojure team)20:10:16

it's fairly common, and that's what `apply` is for

Alex Miller (Clojure team)20:10:50

it may be confusing how to use it here because you would need to spread into a collection constructor, like:

``(apply vector olp->csv->headers (olp->csv->create-rows accounts))``

Alex Miller (Clojure team)20:10:56

but that's another option

Alex Miller (Clojure team)20:10:30

like the `into` option above, would mean copying a lot of data to no benefit

sheluchin20:10:31

What is the rationale behind string/join and string/split putting their "separater" argument in different positions?

Alex Miller (Clojure team)20:10:14

in general, the string functions always take the string first (similar to how collection functions take the collection first)

Alex Miller (Clojure team)20:10:34

string/join is a special case as the separator is often `partial`-ed in

sheluchin22:10:02

Thanks @alexmiller. I did read somewhere - I think in a Stuart Sierra article - that the "main thing" usually comes as the first argument, and seeing as it's the string namespace, I expect the string arg to come first, but the pragmatism makes sense. It would be nice if there was a resource that listed the common "special cases" for reference.

Alex Miller (Clojure team)22:10:15

I think the clojure.string namespace docstring does have some of this in it, not at a computer

Ty22:10:47

How can I map a function to a collection and always pass the same parameter for the second parameter to the function?

dpsutton22:10:03

`(map (fn [x] (the-function x whatever-value-you-want)) coll)`

Stuart22:10:54

If you can change the function and can swap the order of parans then you could use `partial`

dpsutton22:10:21

and shorthand `(map #(+ % 7) [1 2 3])`

phronmophobic23:10:17

Is there a function that is the equivalent of?

``````(defn find-first-match [pred coll]
(some #(when (pred %)
%)
coll))
;; usage
> (find-first-match :b [{:a 1} {:b 2} {:c 3}])
;; {:b 2}``````
If not, what would be a good name for it? I use this idiom at the repl a lot and having a shorthand for it would be really useful.

walterl23:10:56

I tend to end up writing out `(first (filter pred coll))`

phronmophobic00:10:45

If it doesn’t exist, I want an accurate, short name for it. Being concise is a feature for my use case.

walterl00:10:00

`ffilter`? 😝

🎉 1
phronmophobic00:10:22

that’s actually pretty good

phronmophobic00:10:43

matches fnext, ffirst, etc

phronmophobic00:10:30

you’re a genius!

jumar04:10:23

Medley has find-first and a bunch of other useful functions

👍 1
Ben Sless05:10:17

More generally, you can fkeep

Apple13:10:38

``(some #(if (:b %) %) [{:a 1} {:b 2} {:c 3}])``

Ben Sless03:10:18

Like find-first, keep first You can also use xforms and use the some-rf

Ty23:10:44

I did end up using partial actually

Ty23:10:56

The shorthand for lambdas is pretty compelling, though