clojure

New to Clojure? Try the #beginners channel. Official docs: https://clojure.org/ Searchable message archives: https://clojurians-log.clojureverse.org/
2020-09-25T00:16:52.085900Z

Looks good overall. A few small suggestions: * If you want to terminate request processing early, it's good practice to use terminate (http://pedestal.io/api/pedestal.interceptor/io.pedestal.interceptor.chain.html#var-terminate). * You might consider doing something like (assoc-in context [:request :parsed qstring] parsed-param) so that you're just adding data to your context map in the interceptor and not overwriting your request data. * Consider the option of separating the concerns of parsing the query params and validating them into separate interceptors.

2020-09-25T00:17:35.086100Z

Also, there's a #pedestal channel that might be a good place to discuss further.

vncz 2020-09-25T00:18:52.086300Z

All good point. I've read somewhere that Pedestal terminates if the response object is there, that's why I followed the convention

vncz 2020-09-25T00:20:26.086500Z

@codonnell I do not understand the second point — how would assoc overwrite the request data?

2020-09-25T01:42:57.086700Z

I'm not a pedestal expert and it's been a while since I've used the library. IIRC the request data is available in ctx under the :request key. If that is the case and you do (assoc ctx :request {:parsed parsed-param}), then you will dump whatever data was previously associated to :request. If that's not what's happening, then there is no problem. :)

Linus Ericsson 2020-09-25T06:59:39.087600Z

(fn [o] (or (vector? o) (list? o)))

jumar 2020-09-25T12:47:49.090100Z

I'm reading Chapter 6 from Joy of Clojure and in the section about laziness they claim that next is "less lazy" and should print three dots in the example below - but for me it prints also only two dots. Is that something that has been changed in a more recent version of Clojure?

;; rest vs. next (p. 126)
(def very-lazy (-> (iterate #(do (print \.) (inc %)) 1)
                   rest rest rest))
;;=> prints two dots ..


(def less-lazy (-> (iterate #(do (print \.) (inc %)) 1)
                   next next next))
;;=> prints two dots too?!

jumar 2020-09-25T12:49:24.090200Z

Although this works as expected (= stated in the book): Actually, this doesn't work either 😮

(println (first very-lazy))
;;=> prints ".4"
(println (first less-lazy))
;;=> prints ".4" (although it should print just "4")

alexmiller 2020-09-25T12:52:02.090800Z

iterate has been rewritten since JoC was written

alexmiller 2020-09-25T12:53:11.091600Z

it's now both seq and self-reducible and written in Java, so all of the details are different

alexmiller 2020-09-25T12:53:53.091800Z

changed in 1.7

jumar 2020-09-25T12:56:02.092Z

Interesting, thanks!

alexmiller 2020-09-25T13:03:50.092300Z

the point is still generally valid :)

jumar 2020-09-25T13:19:08.092600Z

Yeah, I think it's visible here:

(defn simple-range [i limit]
  (lazy-seq
   ;; nil returned by when will terminate the range construction
   (when (< i limit)
     (print ".")
     (cons i (simple-range (inc i) limit)))))
;; prints 3 dots
(def rrr (rest (rest (rest (simple-range 1 10)))))
;; prints 4 dots
(def nnn (next (next (next (simple-range 1 10)))))

vncz 2020-09-25T13:53:17.094900Z

Quick questions on atoms — if I understood the thing correctly the way they should be used is by dereferencing them once at the beginning of where they're used — and not dereference them every single time that is needed, in order to have the same value for the entire time of the computation.

vncz 2020-09-25T13:54:50.095600Z

…because dereferencing it every single time that is needed might ultimately give two different values

borkdude 2020-09-25T13:55:11.096Z

that's correct, they're mutable, so they can change from under you.

vncz 2020-09-25T13:55:45.096500Z

but if I dereference them once, at the beginning of my computation and save the value using a let binding

vncz 2020-09-25T13:55:59.097Z

I am "protected" — the box can point to something else, the value I dereferenced is immutable

borkdude 2020-09-25T13:56:21.097400Z

if you store an immutable value in the atom, yes

vncz 2020-09-25T13:56:59.097700Z

Ok perfect, that makes completely sense. Thanks @borkdude

borkdude 2020-09-25T13:57:33.098300Z

@vincenz.chianese Note that for updating atoms you generally want to use swap!, if the update function references the current value

borkdude 2020-09-25T13:58:55.099500Z

e.g. don't do this:

(def x (atom 1))
(reset! x (inc @x))
but do this instead:
(swap! x inc)

vncz 2020-09-25T14:00:19.100900Z

@borkdude Oh yeah for sure, I think I've understood the semantic of swap! and reset!

vncz 2020-09-25T14:01:21.101700Z

I was just having some doubts on how the mechanism would make sure that there are no race conditions and weird stuff in multithreads; now that I understood the thing (separate the value from its pointer) it's totally clear.

Aleks 2020-09-25T14:27:13.101900Z

Hey there.

Aleks 2020-09-25T14:28:12.102900Z

I am quite new to Clojure and I cannot really grasp why why str/join is ignoring the last argument here. bb '(-> "some str" (#(str/split %1 #" ")) (str/join "-"))'

Aleks 2020-09-25T14:29:48.104600Z

I understand there are two signatures for clojure.string/join function but I can’t get why the extra argument is ignored here. Using macro for anonymous function of course solves the issue, but shouldn’t this work like this, too. If not - why not?

jsn 2020-09-25T14:32:39.104700Z

1. that should be in #beginners 2. that should probably be ->> (`bb '(->> "some str" (#(str/split %1 #" ")) (str/join "-"))'` )

Aleks 2020-09-25T14:38:27.106800Z

Yeah, thanks.

nwjsmith 2020-09-25T14:38:30.107100Z

The -> macro is going to to thread the return values through in the first argument position. The line you have there ends up compiling to: (str/join (#(str/split %1 #" ") "some str") "-") . I think what you'd like is something like this: (str/join "-" (str/split "some str" #" ")).

nwjsmith 2020-09-25T14:40:22.107500Z

Does that clear things up?

nwjsmith 2020-09-25T14:47:25.110600Z

As you're new to the language, one of the things worth knowing about Clojure is that many of the core functions take a "garbage in, garbage out" approach. So even though your original form evaluates to "-", the call itself has the arguments out-of-order – (str/join ["some" "str"] "-")

👍 1
🙏 1
Aleks 2020-09-25T14:51:45.111200Z

Yeah, I was sure I was using thread-last macro, many thanks. 🙂

Karol Wójcik 2020-09-25T14:59:22.112200Z

Is it possible to use System/getEnv in edn file?

Daniel Stephens 2020-09-25T15:00:47.112300Z

not natively as such but we use https://github.com/juxt/aero which adds some extra tags for them

Karol Wójcik 2020-09-25T15:02:55.112600Z

Ok great. Do you know whether it's possible to use clj with different deps.edn names? Like deps.development.edn deps.production.edn etc?

vlaaad 2020-09-25T15:03:37.112800Z

Aliases are usually used for that...

vlaaad 2020-09-25T15:04:13.113Z

E.g. you have :dev alias with extra paths and deps

Daniel Stephens 2020-09-25T15:04:48.113200Z

👍 https://clojure.org/guides/deps_and_cli#override_deps

Karol Wójcik 2020-09-25T15:05:12.113400Z

Perfect! Thank you!

oxalorg (Mitesh) 2020-09-25T15:07:20.115Z

@ad399 When I'm trying to figure stuff out I usually use the macroexpand-all function from clojure.walk to figure out what is the final form. This should be helpful to debug more issues in the future:

(use 'clojure.walk)
(macroexpand-all '(-> "some str" (#(str/split %1 #" ")) (str/join "-"))
This will return
(str/join ((fn* [p1__9737#] (str/split p1__9737# #" ")) "some str") "-")

Aleks 2020-09-25T15:07:51.115400Z

@mitesh This is very nice, thank you.

👍 1
2020-09-25T16:50:37.117Z

Are there any suggestions or improvements?

(defn take-sorted-by [c n f]
    (let [m ^TreeMap (TreeMap.)
          m-size (volatile! 0)
          m-add (fn [k v] (if-let [a ^ArrayList (.get m k)]
                            (.add ^ArrayList a v)
                            (.put ^TreeMap m k (doto (ArrayList.) (.add v)))))
          m-sub (fn [k] (let [a ^ArrayList (.get m k)
                              size ^int (.size a)]
                          (.remove a (dec size)) ;; (dec size) have to be int type!
                          (when (.isEmpty ^ArrayList a)
                            (.remove ^TreeMap m k))))]
      (doseq [v c]
        (let [k (f v)]
          (if (< @m-size n)
            (do
              (m-add k v)
              (vswap! m-size inc))
            (let [max-key (.lastKey ^TreeMap m)]
              (when (< k max-key)
                (m-sub max-key)
                (m-add k v))))))
      (->> m vals (apply concat))))

  (defn take-sorted-by-naive [c n f] (->> c (sort-by f) (take n)))

  (let [c (range 100000000)
        n 10
        f #(rem % 15000000)]
    ;; (-> (take-sorted-by-naive c n f) prn time) bad idea, Execution error (OutOfMemoryError)
    (-> (take-sorted-by c n f) prn time))

(0 15000000 30000000 45000000 60000000 75000000 90000000 1 15000001 30000001)
"Elapsed time: 2268.525789 msecs"

2020-09-25T16:53:19.117300Z

yep, ofc (:import [java.util TreeMap ArrayList])

2020-09-25T17:05:10.120300Z

In cases where you need to accumulate a result across a sequence, and check for an end condition after each new item, are there any general guidelines on when to prefer loop/recur vs reduce/reduced? It seems like it might be best to prefer reduce if that is sufficient, since it's higher level. But on the other hand I haven't seen that as often and there might be more nuance involved there?

chrisulloa 2020-09-25T17:14:21.121900Z

Here’s a nice little write up on it https://groups.google.com/g/clojure/c/Q9KrgqyToIo/m/0MqKg2WIAwAJ

👍 1
p-himik 2020-09-25T17:14:40.122300Z

I tend to use reduce when there's just one accumulator of sorts. loop for everything else that can't be expressed with other higher-order functions.

➕ 2
2020-09-25T17:18:06.123100Z

2 accumulators = one accumulator 🙂

NoahTheDuke 2020-09-25T18:12:32.124300Z

within a given namespace, is it possible to see which vars aren't defined in it? i mean, which vars are defined elsewhere and required/imported in?

NoahTheDuke 2020-09-25T18:13:58.125500Z

i have a habit of writing :refer :all, and i want to step through my project's namespaces and convert those :refer :all lines into :refer [specific-var] lines

NoahTheDuke 2020-09-25T18:14:42.126300Z

and it's a slow process to change it to be (:require ... [other.namespace]) and then compile and see what's failed, and then add them in one at a time

2020-09-25T18:15:39.126700Z

you might give https://github.com/technomancy/slamhound a try

jdhollis 2020-09-26T17:13:55.188Z

One of my favorite books. Nice.

NoahTheDuke 2020-09-25T18:16:21.127Z

oh that's cool as heck

NoahTheDuke 2020-09-25T18:16:24.127200Z

thank you so much

NoahTheDuke 2020-09-25T18:16:29.127400Z

exactly what i was looking for

borkdude 2020-09-25T18:30:02.128600Z

@nbtheduke clj-kondo can also help with this, provided you have linted all your sources so it can infer where vars are coming from in case of refer all

borkdude 2020-09-25T18:32:48.128700Z

NoahTheDuke 2020-09-25T18:45:13.129Z

i should probably hop into #clj-kondo to ask, but it just says "use alias or :refer" for me. is there something specific I should do to make it figure it out for me?

borkdude 2020-09-25T18:55:35.130900Z

Like I said, you should also lint the other namespace. Also you should have a .clj-kondo dir if you’re doing it from an editor, so it can save data there

NoahTheDuke 2020-09-25T18:55:43.131100Z

okay, cool

vncz 2020-09-25T19:58:49.131800Z

Is there a way to get a collection's item by index and also remove it from the collection, all in one shot?

vncz 2020-09-25T20:02:56.132200Z

Essentially, something better than this:

vncz 2020-09-25T20:05:26.132800Z

Ideally I would like both

vncz 2020-09-25T20:05:30.133Z

The new collection and the extracted item

schmee 2020-09-25T20:08:46.133600Z

vectors aren’t great for that type of thing, depending on what you’re doing maybe you could use an ArrayList instead?

vncz 2020-09-25T20:09:45.134600Z

Well essentially I'd like something like const [elem, newVector] = removeElement(originalVector, index);

vncz 2020-09-25T20:09:56.134900Z

I'm new to Clojure and my knowledge of Java is literally -1

schmee 2020-09-25T20:12:18.135600Z

not a problem! if you can provide some more context I might be able to point you in the right direction

vncz 2020-09-25T20:13:07.135700Z

Well again, I'm looking for a built-in function (if any) to do this:

vncz 2020-09-25T20:14:01.136400Z

user=> (remove-collection-index [9 8 7 6 5 4 3 2 1 0] 3) [6 (9 8 7 5 4 3 2 1 0)]

alexmiller 2020-09-25T20:17:27.137400Z

there isn't a function to do this, and I would encourage you to structure your data in a way that you don't need it

schmee 2020-09-25T20:17:51.137900Z

agree, that’s why I was asking for more context 🙂

vncz 2020-09-25T20:18:36.138700Z

All right! Thanks for the help. I'm trying to get some proficiency in Clojure and I'm trying to implement the "Game of Pure Strategy" game.

vncz 2020-09-25T20:19:21.139600Z

In the game, there's a step where I need to draw an element from a deck and then remove it (the removal is part of the construction of the "next state")

vncz 2020-09-25T20:20:39.139800Z

This is the initialState I start with and then I have a function gameStep that takes such state and provides the new one

vncz 2020-09-25T20:21:40.141Z

I need to draw a card from all the decks, do a comparison and then call the gameStep again (which has a guard clause of course, and is (= 0 (count (:bountyDeck currentState)

vncz 2020-09-25T20:21:55.141400Z

If there'a better way — I'm all for it!

schmee 2020-09-25T20:22:57.142100Z

one idea from the top of my head is to model the deck as a map from index to card

schmee 2020-09-25T20:23:25.142800Z

then the “get and remove” would be as easy as calling (dissoc deck index)

vncz 2020-09-25T20:23:45.143200Z

{:1 1}

vncz 2020-09-25T20:23:47.143400Z

Something like this?

schmee 2020-09-25T20:23:52.143600Z

yeah

vncz 2020-09-25T20:24:08.144Z

:thinking_face: I'm curios now, why is it ok for maps to get and remove and not so ok for vectors?

alexmiller 2020-09-25T20:25:26.145200Z

because maps support removal by key and vectors don't

vncz 2020-09-25T20:25:45.145700Z

Ah ok — so the idea is not that bad, I'm just using the bad data structure if I'm following

schmee 2020-09-25T20:25:52.145900Z

exactly :thumbsup:

vncz 2020-09-25T20:27:54.146600Z

but I'm on the same situation now?

vncz 2020-09-25T20:28:12.146800Z

vncz 2020-09-25T20:28:39.148Z

I get a new map, but not the removed value — I'd still need to lookup the element value manually

schmee 2020-09-25T20:28:40.148100Z

do (get testMap :1) and store that before you dissoc

vncz 2020-09-25T20:28:58.148500Z

Got it, and I'm assuming there's no way to do that in one shot with a built in function

vncz 2020-09-25T20:29:48.148700Z

Wouldn't a set be even better?

schmee 2020-09-25T20:30:02.149100Z

I don’t think so, no

schmee 2020-09-25T20:31:14.149600Z

a set is not ordered, I assume the deck is?

vncz 2020-09-25T20:31:23.149800Z

No, I do not care about the order

schmee 2020-09-25T20:32:05.150700Z

then set is better, yes! sets use disj instead of dissoc, fyi

vncz 2020-09-25T20:32:29.150900Z

Ok, let's then!

vncz 2020-09-25T20:59:38.151500Z

Ok I got it working. It's terrible, I know, but it's a start. I'll go from there, thanks!

p-himik 2020-09-26T14:43:01.181700Z

(= 0 (county bountyDeck)) should be replaced with (empty? bountyDeck). Or just swap the branches in if and replace the condition with (seq bountyDeck). Unless, of course, boundyDeck is some custom collection type. When you want to get-in a path of only keywords, you can just use the -> macro: (-> current-state :firstPlayer :deck). Both shorter and faster. update-in with a path of a single item can be just update. (update-in [:bountyDeck] (disj drawn-card)) and the lines below it don't od anything - you should remove the parentheses around the call to disj.

vncz 2020-09-26T14:46:50.181900Z

@p-himik Thanks for the suggestions — I do have a doubt about the last line indeed. I made a mistake in the copy paste

vncz 2020-09-26T14:46:56.182100Z

What I'm doing at the moment is (update-in [:secondPlayer :deck] #(disj % second-player-card))

vncz 2020-09-26T14:47:09.182300Z

Using an anonymous function, but if there's a way to avoid that, even better. I haven't yet found one.

p-himik 2020-09-26T14:48:36.182500Z

Just use (update-in [:secondPlayer :deck] disj second-player-card)

p-himik 2020-09-26T14:48:54.182700Z

update-in internally does (apply f v args).

vncz 2020-09-26T14:49:05.182900Z

Ah ok I understand, this is because update-in takes an additional array of parameters that will feed to the function after the main arugment

p-himik 2020-09-26T14:49:06.183100Z

When in doubt, check the source code. :)

vncz 2020-09-26T14:49:08.183300Z

Didn't notice that

vncz 2020-09-26T14:49:32.183500Z

vncz 2020-09-26T14:49:39.183900Z

Ok so this is what I have now

p-himik 2020-09-26T14:52:45.184100Z

LGTM

vncz 2020-09-26T14:53:17.184300Z

Glad to hear that!

vncz 2020-09-26T14:53:47.184500Z

I've also reversed the if order as suggested and avoided the new state symbol

vncz 2020-09-26T14:54:01.184700Z

p-himik 2020-09-26T15:39:38.186300Z

One tiny thing - it's better to have a new line right after [current-state] to avoid shifting everything to the right too much and creating too much empty space on the left.

schmee 2020-09-26T15:40:22.186600Z

looking good! :thumbsup: small nitpick/fyi: variables and keywords in clojure are usually `:snake-case` rather than `:camelCase`

vncz 2020-09-26T15:57:26.186800Z

@schmee I've changed them all 🙂

vncz 2020-09-26T15:58:35.187Z

@p-himik Great suggestions, it looks way better now

vncz 2020-09-27T15:00:35.211400Z

It turns out I can use de-structuring on maps as well https://github.com/XVincentX/gops-clojure/commit/f1960a1157f16112b45c76513ec0fd05881d839d

p-himik 2020-09-27T15:02:45.211600Z

I wouldn't recommend using maps-within-maps destructuring - it's much harder to read than a single level destructuring or a maps-within-vector destructuring.

p-himik 2020-09-27T15:04:39.211800Z

I would maybe write it instead as

(defn game-step [{:keys [bounty-deck first-player second-player] :as current-state}]
   ...)
And then you don't really need to create first-player-deck - just use (:deck first player) right where it's needed.

vncz 2020-09-27T15:15:58.212Z

Makes sense — better not go too crazy I guess

vncz 2020-09-25T21:03:08.152600Z

First lesson learned: accessing nested maps can be a pain, so better keep data structures as simple as possible :troll:

emccue 2020-09-25T21:07:28.152700Z

c n f v k m

emccue 2020-09-25T21:07:40.152900Z

those are all pretty unhelpful variable names

schmee 2020-09-25T21:09:48.153600Z

looks good, definitely on the right track! :thumbsup:

emccue 2020-09-25T21:10:13.154100Z

@vincenz.chianese If you want to remove by index and get an item at the same time, you can always use juxt

emccue 2020-09-25T21:10:53.154700Z

(juxt :1 #(dissoc % :1))

emccue 2020-09-25T21:11:04.155Z

will return a vector that is basically

emccue 2020-09-25T21:11:26.155500Z

[(:1 ds) (dissoc ds :1)]

emccue 2020-09-25T21:11:40.155800Z

when called on whatever structure

vncz 2020-09-25T21:12:59.156600Z

Oh interesting

emccue 2020-09-25T21:13:05.156800Z

juxt is generally pretty useful if you want to do things "all in one shot" (logically, there might be multiple passes over data)

vncz 2020-09-25T21:13:53.158Z

I can see! Calls multiple functions on the same arg right?

emccue 2020-09-25T21:14:16.158500Z

(let [[value new-coll] ((juxt #(nth % 3) #(remove (partial = 3) %)) collection)])

emccue 2020-09-25T21:14:26.158800Z

and returns the result in a vector

2020-09-25T23:44:24.159800Z

That’s weird right?

user=> (map #(doto % println) [1 2 3])
(1
2
3
1 2 3)

seancorfield 2020-09-25T23:45:19.160Z

What's weird about it?

2020-09-25T23:45:56.160700Z

Shouldn’t it be outputting?

1
2
3
(1 2 3)

seancorfield 2020-09-25T23:46:27.160900Z

Why?

2020-09-25T23:47:14.162Z

The side effect should trigger before the result is returned for printing right?

seancorfield 2020-09-25T23:47:26.162300Z

map produces a lazy seq, so the REPL starts to print a sequence ( then it has to realize the first chunk of it -- which causes the function to be called on three elements -- and then it can print that chunk.

seancorfield 2020-09-25T23:47:53.163Z

When you mix laziness and side-effects, you should expect interleaving 🙂

seancorfield 2020-09-25T23:48:53.164100Z

Try (map #(doto % println) (range 40)) and you'll see chunking in action.

2020-09-25T23:50:19.166200Z

I suppose that makes sense. Sounds like I’m picking a terrible test case to showcase Clojure’s ability to map over vectors, lists, and hash-maps.

seancorfield 2020-09-25T23:50:39.166800Z

It'll print ( then 0 to 31 (from the println) then the result of the first chunk -- a line with 0 1 2 3 .. 31 -- then it'll print 32 up to 39 (from the println) then the next chunk of the result -- a line with 32 33 .. 39 and the )

2020-09-25T23:50:43.167Z

I’ll just switch to a pure function

2020-09-25T23:50:46.167200Z

I’ll try it

seancorfield 2020-09-25T23:50:49.167400Z

Never mix side-effects and laziness!

seancorfield 2020-09-25T23:51:14.167800Z

If you use mapv it is eager and you won't get interleaving.

seancorfield 2020-09-25T23:51:52.168400Z

(but, yes, a pure function would be a better demonstration -- otherwise you have to explain laziness and chunking!)

2020-09-25T23:53:13.168800Z

I’m surprised I haven’t run into that before, but thanks for explaining it.

2020-09-25T23:53:34.169400Z

Although I suppose I usually print the seq or use a do-seq for that