Fork me on GitHub
#beginners
<
2019-09-23
>
negaamanuel06:09:10

Hi Everyone! I'm a begginer in Clojure, I've been practicing. And I think I'm ready to work fulltime on it. Anyone know begginer level jobs for an experienced Dev on other technologies?

lennart.buit06:09:08

Take a peek into #jobs

ho0man07:09:38

Hi, everyone If we have nested dosyncs would the inner dosyncs start a new transaction or not ? (Is this sentence form the docs mentioning my question, I wasn't sure : "Starts a transaction if none is already running on this thread.") Thanks

jaihindhreddy08:09:18

All nested transactions get absorbed into the outer transaction. So the entire outer transaction is atomic, consistent and isolated from other transactions. The only reason I can come up with for caring whether inner transactions get started and/or retried atomically etc.. is if you have side effects in your transactions, which is a bad idea for multiple reasons. So I guess what I wanted to ask is, why do you care how inner transactions behave?

ho0man11:09:02

Thanks @ No I dont have sideeffects inside my transaction ... and what you described was the functionality that I hoped. (I asked because I constructed transactions using multiple functions, each one having their own dosync. So I wanted to make sure that they all get executed as part of a single transaction)

dharrigan11:09:02

At the moment, I'm learning (tap> ....). I have, in my core.clj a (defn my-spy [message] (log/infof message)). Then, throughout my code, at various places (to aid in debugging), I use (tap> "blah blah value blah blah"). I'm wondering is there a pattern for better tap usage?

davidomarfch14:09:47

Hi. How would you apply a function to a generator so the generated value is the result of calling that function with generated values? I'll explain it better I have a function

(defn make-a-b [a b] {:a a :b b})
And a function
(defn add-c [a-b c] [(:a a-b) c (:b a-b)])
So for example I call
(def x-y (make-a-b 1 2))
x-y
;; => {:a 1, :b 2}

(add-c x-y 3)
;; => [1 3 2]
add-c will only work if a-b have :a and :b keys. Now, I'm spec'ing add-c to generate tests. But I don't know how to spec that a-b must be a result of calling make-a-b with correct values. I've tried this:
(def gen-a-b
  (gen/tuple gen/string-alphanumeric gen/string-alphanumeric))

(gen/sample gen-a-b 3)
;; => (["" ""] ["" ""] ["" "hr"])


(s/def ::a-b
  (s/with-gen
    #(make-a-b (first %) (second %))
    (constantly gen-a-b)))

(gen/sample (s/gen ::a-b) 3)
;; => (["" ""] ["" ""] ["" "hr"])
;; However, I'm expecting to receive something like this, instead:
;; => ({:a "" :b ""} {:a "" :b ""} {:a "" :b "hr"}
I want to do this so I can then go to add-c specs and do:
(s/fdef add-c
  :args (s/cat :a-b ::a-b
               :c string?)
  ;; ...
  )
So the generated tests generate parameters for :a-b using the ::a-b generator

davidomarfch14:09:47

Hi. How would you apply a function to a generator so the generated value is the result of calling that function with generated values? I'll explain it better I have a function

(defn make-a-b [a b] {:a a :b b})
And a function
(defn add-c [a-b c] [(:a a-b) c (:b a-b)])
So for example I call
(def x-y (make-a-b 1 2))
x-y
;; => {:a 1, :b 2}

(add-c x-y 3)
;; => [1 3 2]
add-c will only work if a-b have :a and :b keys. Now, I'm spec'ing add-c to generate tests. But I don't know how to spec that a-b must be a result of calling make-a-b with correct values. I've tried this:
(def gen-a-b
  (gen/tuple gen/string-alphanumeric gen/string-alphanumeric))

(gen/sample gen-a-b 3)
;; => (["" ""] ["" ""] ["" "hr"])


(s/def ::a-b
  (s/with-gen
    #(make-a-b (first %) (second %))
    (constantly gen-a-b)))

(gen/sample (s/gen ::a-b) 3)
;; => (["" ""] ["" ""] ["" "hr"])
;; However, I'm expecting to receive something like this, instead:
;; => ({:a "" :b ""} {:a "" :b ""} {:a "" :b "hr"}
I want to do this so I can then go to add-c specs and do:
(s/fdef add-c
  :args (s/cat :a-b ::a-b
               :c string?)
  ;; ...
  )
So the generated tests generate parameters for :a-b using the ::a-b generator

davidomarfch14:09:39

Thanks in advance.

alexmiller14:09:10

re "How would you apply a function to a generator so the generated value is the result of calling that function with generated values?", that sounds like gen/fmap

alexmiller14:09:16

sorry I didn't read all the rest

davidomarfch14:09:39

That's what I needed. It's fixed now. Thank you!

jaime.sangcap17:09:38

Hi everyone! I’m new to clojurescript stack coming from Javascript background. I’m just wondering what build tool do you prefer these days? Based on what I’ve searched so far, figwheel-main and shadow-cljs are mostly being mentioned. What are the pros & cons of each tool? Can anyone also guide me what other tools do you use and for what purpose? Here are the tools that I’m aware of right now. - reagent (like react) - figwheel (webpack + npm ??) - shadow-cljs (webpack + npm ??) - leiningen (package manager?)

tkjone21:09:05

I address these questions and and more in https://betweentwoparens.com/start-a-clojurescript-app-from-scratch and Sean Corfield does an excellent job digging into lein, boot and clj here https://corfield.org/blog/2018/04/18/all-the-paths/

tkjone21:09:15

RE: figwheel v. shadowcljs You can’t go wrong with either one. My preference is figwheel-main. shadow and figwheel have the samw feature set minus the fact that shadow has built-in support for the npm ecosystem where as if you go with figwheel and want to make use of the npm ecosystem you would have to configure it yourself with webpack like this: https://clojurescript.org/guides/webpack

jr0cket10:09:00

Short version: If you need to use npm packages then use shadow-cljs. Otherwise use figwheel-main. For complex UI's and lifecycles use re-frame, otherwise use reagent There are always other options, but these are the most common at the moment.

jaime.sangcap17:09:49

@ THank you soo much 😃 How could I missed those articles?! Good read, very detailed and beginner friendly.

jaime.sangcap17:09:16

@ @ I will use reagent for now. Between shadow-cljs and figwheel-main, it seems like only figwheel has support for hot module reloading HMR + it supports npm somehow

jaime.sangcap17:09:54

but shadow-cljs out of the box support for npm is really appealing 🙂

jr0cket18:09:29

You can also use http://cljsjs.github.io/ to include JavaScript libraries as simply as Clojure dependencies, as it provides the externs

jaime.sangcap18:09:58

that’s cool. thank you 🙂

jr0cket18:09:39

I recommend listening to https://clojurescriptpodcast.com/ for more background on ClojureScript and how everything works. This is run by a JavaScript developer who also does ClojureScript

jaime.sangcap18:09:36

nice! it seems like the community is not that bad what others are saying

jaime.sangcap18:09:56

thanks a lot @

watchtheblur18:09:21

how does (partition-by identity [coll]) work? It's de-duplicating the collection, but I can't find a way to get clojure to show me what it's doing step by step.

ghadi18:09:02

it's not deduping, but partitioning every time the input doesn't match the previous return value of the predicate (identity)

ordnungswidrig18:09:24

(partition-by identity [2 2 1 2 3 4 5])
=> ((2 2) (1) (2) (3) (4) (5))

watchtheblur18:09:11

If the input is the entire collection, why would it partition by duplicates?

watchtheblur18:09:32

Then what is it doing?

ordnungswidrig18:09:58

Partitioning into a list of collection, splitting whenever the element changes.

watchtheblur18:09:26

How does it do that?

ordnungswidrig18:09:23

It’s iterating over the collection entries. Look at the source, but beware: nobody wants to know how the sausage is made.

watchtheblur18:09:51

I read the source, but I'm a beginner so the source isn't for beginners

ghadi18:09:00

([f coll]
     (lazy-seq
      (when-let [s (seq coll)]
        (let [fst (first s)
              fv (f fst)
              run (cons fst (take-while #(= fv (f %)) (next s)))]
          (cons run (partition-by f (lazy-seq (drop (count run) s))))))))
that's the relevant part of the source

watchtheblur18:09:02

I read the source for partition-by I mean

ordnungswidrig18:09:03

It’s highly optimized

ghadi18:09:45

it's not optimized at all -- it's just probably hard to read for a beginner

ordnungswidrig18:09:12

@ghadi when you look at the full sources, it makes use of volatile and reducers.

ghadi18:09:36

it applies the predicate, then eats anything else that matches the predicate

ghadi18:09:49

(cons fst (take-while #(= fv (f %)) ....)

ghadi18:09:07

then -- it drops what it ate! (drop (count run) ...)

watchtheblur18:09:14

I'm trying to get an intuition on what partition-by is doing. The clojure doc says that it splits each time the function (in this case identity) returns a new value

ghadi18:09:16

and processes the rest with the same process

ghadi18:09:09

de-duping would mean that input items are omitted from the output collection, but partition-by doesn't remove anything, just splits whenever the input changes

ghadi18:09:15

where change is defined by the predicate

watchtheblur18:09:55

but since identity always returns the entire collection

ghadi18:09:12

might want to try: (partition-by #(< % 10) [0 1 5 10 12 14 0 20 0]) to clarify

ordnungswidrig18:09:42

identity makes partition-by compare by the actual collection value.

watchtheblur18:09:59

I'm sorry for the dedupe confusion @ghadi. I didn't mean to type dedupe

ordnungswidrig18:09:03

whenever that changes, it add another list to the result.

ghadi18:09:51

the word collection is also confusing the example simple_smile -- partition-by examines individual inputs of the input collection

ghadi18:09:06

user=> (partition-by #(< % 10) [0 1 5 10 12 14 0 20 0])
((0 1 5) (10 12 14) (0) (20) (0))

watchtheblur18:09:43

so is the comparison in @ordnungswidrig example [2 2 1 2 3 4 5] vs [2 2 1 2 3 4 5]

ghadi18:09:46

the predicate in that example returns true or false, and partition-by splits things up every transition from t->f or f->t

watchtheblur18:09:55

and it walks 7 times down the vector?

ordnungswidrig18:09:18

@watchtheblur no, it’s comparing 2 vs. 2 then 2 vs. 1

watchtheblur18:09:52

I suspected that it was, but I can't get clojure to show me step by step what it's doing

watchtheblur18:09:42

how can I see what is happening for things I don't understand in the future?

andy.fingerhut18:09:32

one possible way is to copy the definition of a function to your own, with a different name, and modify it, e.g. add println or other kinds of debugging statements to it. Then try calling your modified version to see what happens, starting with small inputs.

andy.fingerhut18:09:59

Another is to use a source level debugger that can step through the execution, but I cannot recommend a particular one as I haven't used one.

watchtheblur18:09:07

so for @ordnungswidrig example, the 2 from f is compared with the 2 from the t predicate first, then the 2 from f is comparing the 1 from the t (skipping the second 2). and so on?

watchtheblur18:09:44

then it loops back to the 2nd 2 from f, and repeat for all elements in t?

ordnungswidrig18:09:05

uhhhm, I guess it starts with 2 2 giving ((2 2))), then 2 1 giving ((2 2) (1))

watchtheblur18:09:23

@andy.fingerhut Thanks for the suggestions, I'll try both!

watchtheblur18:09:09

I guess that's where I get confused. Doesn't identity always return the entire collection?

andy.fingerhut18:09:21

When adding println statements, note that you should be able to take any expression like (x y z) anywhere in the code, and change it to (do (println "I want to know x=" x "and y=" y "but I don't care about z") (x y z)). The (do ...) expression evaluates all of its subexpressions in the order given, then returns the value of the last one.

ghadi18:09:32

@watchtheblur the predicate is never called on the collection, only on individual elements of the collection

ordnungswidrig18:09:18

(defn pb [f coll]
  (reductions (fn [result x]
                (if (= (f x) (some-> result last first f))
                  (cons (cons x (last result)) (butlast result))
                  (cons (list x) result)))
          nil
          coll))

watchtheblur18:09:20

oh! so it's lazily eval as it walk down the predicate?

ghadi18:09:50

as it walks through the collection

ghadi18:09:16

but yes, pretty much

watchtheblur18:09:44

i suspected that, but it would really help if i could see it as it happens...

ordnungswidrig18:09:49

This is an example implementation of what is logically happening. I used reductions so it will return a list of the intermediate results instead.

ordnungswidrig18:09:37

(Does not work correctly with empty collection, but you might get the idea)

watchtheblur18:09:29

Thanks @ordnungswidrig! I'll study that code. (It'll take a while :p)

watchtheblur18:09:43

and thanks @andy.fingerhut and @ghadi!

jr0cket10:09:46

As part of solving a 4Clojure challenge, I implement a simplified version of partition in this video. I also set through the code with a debugger, so you can see exactly what the code is doing.

jr0cket10:09:27

There are many more videos in the playlist, hopefully you find them of interest. Feel free to ask if you have questions (I like to try make these videos better)

watchtheblur00:09:50

Thanks @! I took a look at https://practicalli.github.io and also found your other 4clojure series. Really great content that you're making, I really appreciate it! I can't watch your live recordings because of timezone difference. I was wondering if you know of a way to find clojure study groups, virtual and/or in person?

jr0cket00:09:03

Try searching for Clojure on http://meetup.com and take a look at the #events channel for anything local to you.

jr0cket00:09:55

There is also #remote-meetup

watchtheblur16:10:49

Thanks for the suggestions @! I'll check them out!

seancorfield19:09:02

@watchtheblur Does this help explain the behavior?

user=> (defn id-print [x] (println "looking at" x) x)
#'user/id-print
user=> (partition-by id-print [2 2 1 2 4 3 5])
(looking at 2
looking at 2
looking at 1
looking at 1
(2 2) looking at 2
looking at 2
(1) looking at 4
looking at 4
(2) looking at 3
looking at 3
(4) looking at 5
looking at 5
(3) (5))
user=> (defn even-print? [n] (println "looking at" n "is it even?" (even? n)) (even? n))
#'user/even-print?
user=> (partition-by even-print? [2 2 1 2 4 3 5])
(looking at 2 is it even? true
looking at 2 is it even? true
looking at 1 is it even? false
looking at 1 is it even? false
(2 2) looking at 2 is it even? true
looking at 2 is it even? true
(1) looking at 4 is it even? true
looking at 3 is it even? false
looking at 3 is it even? false
(2 4) looking at 5 is it even? false
(3 5))
user=> 
This shows that the predicate may be called more times than there are elements in the collection but it also shows how the partitioning changes based on the result of the predicate.

watchtheblur20:09:00

Wow! That's what I was looking for! I was looking for a way to see the stack, but this gives me a hint at how to understand the process. Thanks @!

watchtheblur15:09:50

Hi @, I ran your code in a repl, but got a slightly different output. I was wondering if you had any insight on why they are different? Here's mine:

watchtheblur15:09:58

(defn id-print [x] (println "looking at" x) x)
=> #'cursive-test.core/id-print
(partition-by id-print [2 2 1 2 4 3 5])
looking at 2
looking at 2
looking at 1
looking at 1
looking at 2
looking at 2
looking at 4
looking at 4
looking at 3
looking at 3
looking at 5
looking at 5
=> ((2 2) (1) (2) (4) (3) (5))

seancorfield15:09:15

What repl was that?

seancorfield15:09:03

I'm guessing Cursive -- and it's messing with the output, separating stdout and results, which obscures what is really going on.

watchtheblur15:09:39

yeah, I tried it in cursive, and then also windows command line prompt using lein repl Both had the same output. Should I try it lein repl on a linux platform?

watchtheblur16:09:51

Ahh, I figured it out. I was using something called "nREPL" via cursive. Once I switched to clojure.main, I got the same output. Thanks again @!

seancorfield16:09:04

When trying to understand the behavior of something in Clojure, it's often worthwhile to use the CLI/`deps.edn` command line REPL just to ensure no tooling is messing with your results. Cursive, in particular, tries to "help" by managing the REPL experience more tightly -- and nREPL-based tooling often adds middleware to customize the behavior of evaluation.

mattias50419:09:38

Argh. How do I refer to the thing being mapped in a map call? I’m likely very confused, but something like (map (print (str % ”is a thing”)) [”something” ”else”]) if that makes sense.

noisesmith19:09:59

(print ...) returns nil, which isn't callable as a function

hiredman19:09:35

usually people just say you map over a collection

hiredman19:09:56

in a not precise way

hiredman19:09:03

more precisely you might say you map over a seq or something seqable (map internally calls seq on whatever you pass in)

davidomarfch19:09:14

I'm calling my spec-check tests like this:

(deftest subway-line-test
  "Check subway-line"
  (is (sc/spec-check `subway-line {})))

(t/check `subway-line)
How could I specify the :num-tests ? I tried adding that key-val to {} in the deftest:
(deftest subway-line-test
  "Check subway-line"
  (is (sc/spec-check `subway-line {:num-tests 100})))
But doesn't work. How could I achieve it?

seancorfield20:09:14

what is that spec-check function?

davidomarfch20:09:16

Found here. https://ask.clojure.org/index.php/8590/clojure-spec-alpha-check-inside-clojure-testing-framework

(defn spec-check [fn-to-check options]
  (let [results (t/check [fn-to-check] options)]
    (if (some :failure results)
      (do
        (println "\nFailed specs:")
        (doseq [result results
                :when (:failure result)]
          (println (:sym result))
          (pp/pprint (or (ex-data (:failure result))
                         (:failure result)))))
      true)))

seancorfield20:09:51

Ah, OK, so you are using my suggested function...

davidomarfch20:09:39

Hmm, now that I realize, the two calls are not even related.

seancorfield20:09:51

That check function does not take a :num-tests option.

davidomarfch20:09:23

I was testing two times. One with the spec-check function and one with check. Funny how I didn't even realize that. Thanks.

seancorfield20:09:59

I think you need {:clojure.spec.test.check/opts {:num-tests 100}}

davidomarfch20:09:06

That worked. Thanks!

kevin.zemon23:09:06

Hello! I am trying to convert:

(do-stuff x y :a "a" :b "b" :c "c")
to something more like:
(def value-set [[:a "a" :b "b" :c "c"]]
(loop [i 1]
  (do-stuff x y (nth value-set i))
  (if should-recur (recur (inc i)))
How would I do that? Assume I can't change do-stuff, but anything else is fair game. I tried looking at apply, but that isn't quite going to work here.

lilactown23:09:50

unfortunately you would have to do something like a macroexpansion to get that to work

lilactown23:09:17

keyboard args don’t play with well passing in args as data

christian.gonzalez23:09:29

(apply (partial do-stuff x y) (nth value-set i))

kevin.zemon23:09:34

oof, There's no compiler key like # or ' to expand it out?

lilactown23:09:08

your best bet is to define a new function that wraps do-stuff with one that takes your vector (or map, or whatever)

kevin.zemon23:09:41

Actually, it looks like @christian.gonzalez’s solution works.

lilactown23:09:58

huh, surprising 🤔

christian.gonzalez23:09:01

it’s the same thing as what @lilactown suggests, wrapping do-stuff

kevin.zemon23:09:26

ty, that would have taken me a long time to get.

christian.gonzalez23:09:47

doesn’t apply work though? (apply do-stuff x y (nth-value-set i))

christian.gonzalez23:09:14

i just tried in repl it seemed to work for a small example i made

kevin.zemon23:09:33

oh, yes, it looks like it does.

kevin.zemon23:09:47

ok, I was just doing the apply wrong.

christian.gonzalez23:09:56

https://clojuredocs.org/clojure.core/apply has some examples (apply f args) (apply f x args) (apply f x y args)

kevin.zemon23:09:23

I had been trying (apply (do-stuff x y) (nth value-set i))

christian.gonzalez23:09:41

ahh yeah tricky =P

christian.gonzalez23:09:05

apply takes in a function, when you wrap in parens it will evaluate

christian.gonzalez23:09:11

and not necessarily return a function

kevin.zemon23:09:42

I've not had to mess with unlimited arity before, let alone in clojure, wasn't really sure how to pass a vector into the & args

kevin.zemon23:09:48

The madness you've helped me construct:

(apply are [x y] (= (attr driver :name (name x) :value) y)
           (nth sled-settings-gui-values (dec slot-number)))

kevin.zemon23:09:12

But, it let's me loop through doing the same process and be able to feed a different set of values in for each iteration.

kevin.zemon23:09:46

It doesn't look like apply can take a macro (which are is)

christian.gonzalez23:09:01

the vector you’re passing in has a fixed length?

kevin.zemon23:09:45

um, it's known at compile time, but I don't know if each vector is the same length.

kevin.zemon23:09:09

(The vectors are values that I'm defining above)

kevin.zemon23:09:11

Yes, it looks like 16 arguments (8 keys followed by 8 strings) in each.

christian.gonzalez23:09:27

you’ll have to wrap that macro in a function i think

christian.gonzalez23:09:49

i don’t know how to handle a variable number of args though

christian.gonzalez23:09:32

Was thinking of something like this (apply #(some-macro %1 %2 %3) [1 2 3])

kevin.zemon23:09:29

I think %& works

kevin.zemon23:09:44

"Don't know how to create ISeq from: clojure.lang.Symbol"

christian.gonzalez23:09:50

not sure about the %& here