Fork me on GitHub
#beginners
<
2020-05-29
>
Brandon Olivier01:05:01

I'm working on a re-frame app, and I find myself sprinkling the shape of the app-db all over my reg-sub and reg-event-fx calls. It feels like a smell to me, but I'm not sure if that's just idiomatic for clojure

Brandon Olivier01:05:06

for instance, I have some reg-sub that uses (get-in db [:foo :bar :baz]). Should I be reusing an rf/subscribe call there?

Drew Verlee02:05:37

If I recall correctly subscriptions set up state, so it might make things faster. But I wouldn't see it as necessarily "cleaner" from a readability standpoint. Might wanna ask in #re-frame

Brandon Olivier01:05:30

It makes things more difficult in the REPL, but I also don't know if that should be a guiding principle either.

aisamu02:05:33

Reusing the subscriptions has the advantage that it will be shared between all the "users" of that (components or other subscriptions), but I agree that it may introduce unneeded ceremony if you're not sharing anything. But who knows what will be shared tomorrow...

Drew Verlee02:05:39

If the query target is really shared I think it's safer to capture that, subscription or other wise. The link is visable and updaters should see how the check how query is called. Without the link, no one can. I'm not thinking in reframe though, which is going to be the real arbitrar here.

Daniel Östling05:05:49

For style guide, is this what people use or something else? https://guide.clojure.style/

seancorfield05:05:33

That's probably the most widely referenced style guide. I'd suggest looking at some of the linting tools: clj-kondo in particular, but also Eastwood and maybe Kibit.

seancorfield05:05:57

It's good to read the discussions in the Issues as well, for the style guide @danielostling https://github.com/bbatsov/clojure-style-guide/issues

Daniel Östling08:05:52

Okay, thanks! :)

hanDerPeder10:05:27

Using a recursive spec, the presens of s/and seems to affect the result even though there is just one predicate. I would expect (s/and pred) to be equivalent to pred. Am I missing something?

(s/def ::list (s/+ (s/cat :s symbol? :r (s/? ::list))))
(s/conform ::list '[a [b]]) ;; => :clojure.spec.alpha/invalid
(s/explain-str ::list '[a [b]]) ;; => "([b]) - failed: Extra input in: [1] spec: :user/list\n"

(s/def ::list-and (s/+ (s/cat :s symbol? :r (s/? (s/and ::list-and)))))
(s/conform ::list-and '[a [b]]) ;; => [{:s a, :r [{:s b}]}]

👍 4
seancorfield15:05:04

I think this is due to s/? being a sequence regex and when you wrap s/and around ::list-and like that, you're essentially saying "this is a sub-spec" and it doesn't get "unrolled" by s/? like a plain spec or predicate would.

seancorfield15:05:41

It would be like wrapping something in s/spec (which can be used to prevent unrolling of sequence regex forms).

Alex Miller (Clojure team)15:05:50

use s/& to prevent that

seancorfield16:05:34

So (s/? (s/& ::list-and))

hanDerPeder19:05:06

i dont follow. s/& yields the same error as the ::list spec

(s/def ::list-amp (s/+ (s/cat :s symbol? :r (s/? (s/& ::list-amp)))))
  (s/explain-str ::list-amp '[a [b]])
  ;; => "([b]) - failed: Extra input in: [1] spec: :user/list-amp\n"

seancorfield19:05:09

Yes, that's what Alex was saying was equivalent. If you want [b] to be valid, wrap ::list in s/spec (which is what I said would behave like s/and). It wasn't clear which behavior you wanted...

hanDerPeder19:05:05

ok, so to do recursion you need something that “marks” the recursive step as a sub-spec? s/spec, s/and etc..

seancorfield20:05:21

It's not about recursion, it's about whether you want a sequence regex unrolled or not. You haven't said which behavior you want.

seancorfield20:05:14

Do you want (s/conform ::list '[a [b]]) ;; => :clojure.spec.alpha/invalid or do you want that to conform/succeed?

hanDerPeder09:06:06

I want it to conform. Think I have enough to figure it out now. Thanks very much for the help!

Cas Shun13:05:28

I recently saw an interesting string building "trick" of (->> ["Line 1", "Line 2", "Line 3"] (str/join \newline)) (for multiline strings) I'm curious if there's any other similar common idioms for string templating/building.

👍 4
hindol18:05:46

Anyone used Java Lombok annotated class from Clojure? My code does not seem to find the accessors. The class is here: https://github.com/AzureAD/microsoft-authentication-library-for-java/blob/dev/src/main/java/com/microsoft/aad/msal4j/PublicClientApplication.java It inherits from AbstractClientApplicationBase which has the Lombok annotations. The code I am trying to run,

(def client
  (-> (PublicClientApplication/builder "<client_id>")
      (.authority "")
      .build))
The error I am getting: No matching method authority found taking 1 args for class com.microsoft.aad.msal4j.PublicClientApplication$Builder Decompiled AbstractClientApplicationBase: https://pastebin.com/xnXHhpN3 Decompiled PublicClientApplicaton: https://pastebin.com/TH4vSKcN

noisesmith19:05:26

private String authority;
I wouldn't expect this to be available to any clojure code without reflection hacks

noisesmith19:05:44

oh I see there's also a public authority override lower down - I don't know enough about java to go much further than that

noisesmith19:05:48

never mind, the AbstractClientApplicationBase is the one that matters here and its authority method is public

hindol19:05:02

Somehow Clojure is not seeing the methods inherited from the abstract base class.

noisesmith20:05:33

clojure doesn't use the java source, it just goes by the bytecode, so anything java can find, clojure should find too

noisesmith20:05:45

but I admit I'm not a java or lombok expert

hindol20:05:53

I now don't think it is related to Lombok at all. Lombok did it's thing and generated the Java class.. Maybe I am doing something very silly.

noisesmith20:05:15

it might help to make this work via very simple java code first then translate?

noisesmith20:05:31

agreed that lombok shouldn't be making a difference here

jacklombard19:05:52

Hello, I want to introduce clojure spec to validate API endpoints. The parsed response naturally does not have namespaced keywords. How do I go about validating the data? Should I simply use unqualified keys? Where should I keep my spec?

Alex Miller (Clojure team)19:05:03

you can use s/keys with :req-un for unqualified keys

Lukas20:05:13

Hey guys, a few days ago I found this tweet https://twitter.com/TimSweeneyEpic/status/1265451572353552384 and I came up with a solution for clojure

(defn printxy [x]
  (dotimes [n x] (println
                  (apply str
                         (concat
                          (repeat n "X")
                          (repeat (- x n) "Y"))))))
I'm just curious what are other approaches to solve this?

raspasov20:05:23

@lukas.block I believe your solution is incomplete, since I believe the question asks for every permutation

Lukas20:05:08

:thinking_face: ur right the output has to get reverted

raspasov20:05:42

@lukas.block

(map
  #(apply str %)
  (clojure.math.combinatorics/selections ["x" "y"] 10))

raspasov20:05:53

😝 sort of cheating, but works

raspasov20:05:26

(map #(apply str %) (clojure.math.combinatorics/selections [“x” “y”] 4)) => (“xxxx” “xxxy” “xxyx” “xxyy” “xyxx” “xyxy” “xyyx” “xyyy” “yxxx” “yxxy” “yxyx” “yxyy” “yyxx” “yyxy” “yyyx” “yyyy”)

raspasov20:05:09

Don’t run it with a high number, your CPU will 🤯 lol

dpsutton20:05:38

seems like you aren't "testing your programming language's expressiveness" any longer

noisesmith20:05:42

can't you do this with standard doseq?

raspasov21:05:10

@noisesmith not sure… that variable “n” length is the issue I think

noisesmith21:05:45

yeah - fiddling with it a bit I think we need nested for plus distinct

noisesmith21:05:20

and I don't think clojure can do this idiomaticallywithout self-call recursion either

raspasov21:05:19

This is sort of a bit masking problem… wonder if you can use something with bits to do it… that would be from Java

noisesmith21:05:38

you can use bits in clojure

noisesmith21:05:16

right you would built a permutation out of a range of N! numbers from 0 up

noisesmith21:05:44

then use bit-shift-left of 1 recursively to build the "flag checks" that tell you if a given position is "X" or "Y"

noisesmith21:05:58

bitwise is the easy way to do this for sure

noisesmith21:05:34

@raspasov the other trick is we need to use bigints for this as the original post specifies not being limited to some maximum input size

raspasov21:05:49

I think we’re beyond the #beginners channel here lol

noisesmith21:05:23

(import (java.math BigInteger))

(defn xys
  [n]
  (let [permutations (.shiftLeft BigInteger/ONE n)
        values (->> BigInteger/ZERO
                    (iterate #(.add % BigInteger/ONE))
                    (take permutations))]
    (doseq [bitfield values
            index (range n)]
      (print (if (.testBit bitfield index)
               'X 'Y))
      (when (= index (dec n))
        (newline)))))

noisesmith22:05:47

why not, I made hinted versions of xys and an alternate xys-loop that uses recursion instead of collection ops

(import (java.math BigInteger))

(defn xys
  [n]
  (let [permutations (.shiftLeft BigInteger/ONE n)
        values (->> BigInteger/ZERO
                    (iterate #(.add ^BigInteger % BigInteger/ONE))
                    (take permutations))]
    (doseq [bitfield values
            index (range n)]
      (print (if (.testBit ^BigInteger bitfield index)
               "X" "Y"))
      (when (= index (dec n))
        (newline)))))

(defn xys-loop
  [n]
  (let [target (.shiftLeft BigInteger/ONE n)]
    (loop [^BigInteger permutation BigInteger/ZERO]
      (when (< permutation target)
        (loop [index 0]
          (if (= index n)
            (newline)
            (do (print (if (.testBit permutation index)
                         "X" "Y"))
                (recur (inc index)))))
        (recur (.add permutation BigInteger/ONE))))))
the performance is only slightly better without collections
(cmd)user=> (time (binding [*out* (io/writer "/dev/null")] (xys-loop 20)))
"Elapsed time: 10609.954857 msecs"
nil
(cmd)user=> (time (binding [*out* (io/writer "/dev/null")] (xys 20)))
"Elapsed time: 11120.227152 msecs"
nil

👍 4
noisesmith22:05:24

(the rebinding of *out* factors out some of the overhead time in printing, and avoids needing to do impossible scrollback)