Fork me on GitHub
#beginners
<
2020-02-16
>
Kamuela00:02:22

(let [a-promise (promise)]
  (something))

;; Now I can suddenly use a-promise?
(println @a-promise)

Kamuela00:02:56

I had always assumed anything in the let form had a contained scope

rodolfo00:02:08

As far as I know, let indeed never leaks scope like this - evalulating this code gives me Unable to resolve symbol: a-promise in this context, which confirms your correct assumption.

rodolfo00:02:11

If you are currently able to use a-promise outside the let like your code shows, the only explanation would be if you already had an a-promise in your scope outside the let (could very well happen if you're in a REPL and you have defined it previously)

rodolfo00:02:00

But in this case, the a-promise outside the let would not be the same value as the one defined inside

Kamuela00:02:47

It’s possible I misread it, but it was in an explanation of promise usage in a book I’m reading

👍 4
Kamuela00:02:53

That’s why I was confused

Kamuela01:02:48

I’ve absolutely misread it... the use was within the let block. Doh. Well at least I understand something

seancorfield01:02:27

@kamuela Was the example returning the promise as the value of the let block with code that delivered the value to that promise happening "elsewhere"?

Kamuela01:02:44

No the example was using the promise within the let block, I just didn’t realize it because of the formatting

4
Piotr Brzeziński10:02:24

Hey! Quick question 🙂. I want to split a vector into [matchingPred] [notMatchingPred] I thought that this

(split-with even? [1 2 3 4 5])
would give me something like [(1 3 5) (2 4)] but it returns [() (1 2 3 4 5)] instead. Why is that?

Piotr Brzeziński10:02:39

group-by gives me almost the expected result cause it returns {true [2 4], false [1 3 5]}. Should I use that and just get rid of false/true keys by mapping?

Piotr Brzeziński10:02:22

Yeah, I went that way, and it worked, I’m not sure if this is the clojure way so please let me know 🙂

Jakob Durstberger10:02:15

Check out the docs for split-with

([pred coll])
  Returns a vector of [(take-while pred coll) (drop-while pred coll)
1 is not even so it won't be put in the first collection and the rest won't then either. Using group-with sounds good to me

Tzafrir Ben Ami10:02:16

split-with according to its doc "returns a vector of [(take-while pred coll) (drop-while pred coll)]". Note that take-while does not returns a sequence of items that matches your predicate (all even numbers), but rather (in "plain" words) returns a sequence of items until the first item that does not match your predicate - the first odd number So take-while even? [1 2 3 4 5] returns an empty sequence since the first item in your vector [1] is not even. However, take-while odd? [1 2 3 4 5] returns a (1) since odd? 1 returns true, while odd? 2 returns false Similar logic applies to drop-while

mmeix11:02:56

@peb.brzezinski Maybe you want [(filter even? coll) (remove even? coll)] ?

Piotr Brzeziński11:02:37

Ahh, thank you, that makes sense. I misunderstood [(take-while pred coll) (drop-while pred coll)] this part.

Noah Bogart11:02:40

Depending on the size of the vector, you could write a reduce fn to return a tuple of [(even-vals) (odd-vals)]

Noah Bogart11:02:19

Something like (reduce (fn [[fst snd] n] (if (even? n) [(conj fst n) snd] [fst (conj snd n)])) [[] []] coll)

👍 4
mmeix11:02:17

or ((juxt (partial filter even?) (partial remove even?)) coll) 😋

mmeix11:02:06

or maybe better readable: (->> coll (group-by even?) vals)

Matti Uusitalo12:02:57

Risky, as the order of results is unspecified. It might work like you expect, it might not.

Matti Uusitalo12:02:42

Though I'm sure you'd get deterministic results in a benchmark

mmeix12:02:08

ah, you are right!

mmeix12:02:21

then (defn group-with [pred coll] [(filter pred coll) (remove pred coll)])

hindol13:02:48

Order of vals or order of group-by, which one's non deterministic? I kind of liked this solution as this is single pass. Otherwise a reduce is best.

Matti Uusitalo13:02:10

Group by returns a hash map. Order of map entries is unspecified.

hindol13:02:34

Yeah, but there will only ever be two entries. If we know the evens and odds are properly ordered, we are okay.

hindol13:02:13

Like this,

(defn group-with
  [pred coll]
  (let [grouped (group-by pred coll)]
    [(grouped true) (grouped false)]))

(group-with (complement even?) [1 2 3 4 5])

Ben Sless07:02:50

I experimented with this some time ago, you can find the results here: https://gist.github.com/bsless/948319259b542126b57cc1c08b3549f2 Tested for input size of 1e6, found best performance for

(defn splitv [pred coll]
  (reduce
   (fn [[xs ys] x] (if (pred x) [(cons x xs) ys] [xs (cons x ys)]))
   [() ()]
   coll))

👍 8
Ben Sless07:02:34

note, order is reversed

hindol08:02:14

That's good to know.

hindol13:02:19

@mmeix A variant of yours, with deterministic ordering,

(defn group-with
  [pred coll]
  (let [grouped (group-by pred coll)]
    [(grouped true) (grouped false)]))

(group-with even? [1 2 3 4 5]) ;; => [[2 4] [1 3 5]]

Michael Stokley18:02:47

is there a consensus around unit testing private functions? looks like it can be done with the #' macro but it's not clear if that is a hack or considered harmful

Michael Stokley18:02:38

seems one school of thought holds that a function should either be unit tested or private, but not both

hindol18:02:55

I belong to this school of thought. Having too many unit tests really pins down the implementation which makes it difficult to change.

Lennart Buit18:02:14

I think its an argument that can fall both ways: A benefit to not unit testing your private function is that you keep your implementation flexible. A downside is that testing only your public API may be hard, leading to missed cases.

seancorfield18:02:29

I mostly don't unit testing private functions, but I also tend not to make functions private in the first place.

☝️ 4
seancorfield18:02:54

There are exceptions to both parts of that, that are driven somewhat by gut feel, based on nine years of doing Clojure (and learning a lot along the way -- I used to use private functions a lot more and I also used to write more tests for private functions!).

Lennart Buit18:02:26

I think the goal should be to show that your public API works as advertised ^^ — Not the other way around

seancorfield19:02:53

Lately I've been doing more generative testing on private functions, to verify their implementations, rather than unit testing them.

Michael Stokley19:02:18

generative testing - like haskell's quick check?

seancorfield19:02:31

Yes, org.clojure/test.check

Lennart Buit19:02:34

yes, test.check in clojure land

Lennart Buit19:02:44

usually fueled by clojure.spec

seancorfield19:02:54

Yeah, what he said!

seancorfield19:02:07

I was literally just typing a bit about Spec 🙂

Lennart Buit19:02:30

Do you have some publicly shareable examples @U04V70XH6? I am interested in seeing generative tests on unit level that don’t just repeat the implementation

seancorfield19:02:47

Nothing public, sorry.

👍 4
seancorfield19:02:02

The other thing is using clojure.spec.test.alpha/check to generatively exercise an fdef.

didibus21:02:45

I consider it canonical

didibus21:02:02

I unit test and mock many private functions through it

didibus21:02:37

I'm normally in the camp of only test the public interface od your unit. But things are different in Clojure

didibus21:02:06

The unit is at the function level, not the class/namespace. Your private fns should all be pure already, so tests for a pure functions doesn't prevent refactoring the way it does on non pure private class methods

didibus21:02:24

And your IO should either be done by the caller with the data passed in as input, or it should be isolated into private fns that only do the IO, for the latter, mocking those become quite useful

rodolfo18:02:23

@michael740 I do use it and have seen many people using it when testing private fns. I don't see a harm in it, although I've only done it in very rare cases. Whenever possible I try to either keep fns public but organized in internal namespaces, or test from the API layer only.

8
jumpnbrownweasel19:02:43

Question on file/line metadata attached to forms (not vars) by macros, see thread

andy.fingerhut19:02:51

I was about to suggest that. There might be a one or two people here who might know, but #clojure channel is better target rich environment for your question, which most people never dig into for Clojure

Baris Aydek21:02:54

Hi. I'm using threading (->) and want to divide 1 over the result

(->
    10
    (/ 1)) 
Basically I want to get 1/10 but getting 10/1 instead, and I don't want to use (->>) for this case. I also tried using lambda macro but didn't work (syntax error)
(->
    10
    #(/ 1 %)) ;Syntax error (ClassCastException) compiling fn*...
Any suggestions?

seancorfield21:02:43

(->> 10
     (/ 1))

seancorfield21:02:57

You can nest ->> inside ->

seancorfield21:02:22

(-> x
     (stuff)
     (->> (/ 1))
    (more-stuff))

seancorfield21:02:49

The reason -> into #(/ 1 %) doesn't work is because -> is a purely syntactic transform, so it it trying to thread the value (`10` here) into the syntactic form for #(/ 1 %) which is read as (fn [%] (/ 1 %)) so it would produce (fn 10 [%] (/ 1 %))

Baris Aydek21:02:53

oh, now it makes sense. yeah this solves my problem. Thank you!

seancorfield21:02:23

@baris.aydek Another possibility is this, but I think it's uglier than dropping ->> into the -> pipeline:

(-> 10
    (#(/ 1 %)))
The extra parentheses mean you get (#(/ 1 %) 10) after the syntactic transform.

Baris Aydek21:02:56

i prefer ->> it's more readable