Fork me on GitHub
#clojure
<
2019-09-23
>
danielgrosse05:09:52

I have map of lists and would turn it into a list of maps eg.:

{:a (1 2) :b (2 3)} -> ({:a 1 :b 2} {:a 2 :b 3})
. How could I do this? Or better a list of lists to a list of maps with a given set of keys:
((1 2) (1 2)) (:a :b) -> ({:a 1 :b 2} {:a 2 :b 3})

jumar06:09:29

Assuming you wanted to write ((1 2) (2 3)) ... in the last code snippet I'd do something like this:

(let [my-keys [:a :b]
      my-values [[1 2] [2 3]]]
   (map (fn [values]
               (zipmap my-keys values))
      my-values))

andy.fingerhut06:09:46

Did you mean for your second example to be more like this?

((1 2) (3 4)) (:a :b) -> ({:a 1 :b 2} {:a 3 :b 4})

danielgrosse06:09:18

yes your right. @U06BE1L6T already has a solution.

dazld13:09:04

can I big up an amazing library here? I don’t see it being mentioned much, but it’s become an essential part of our toolset: https://github.com/alexanderjamesking/spy

dazld13:09:04

making spies is super easy, and the api is great!

jsabeaudry16:09:46

This test only evaluates the first println first at the first execution of the test: (deftest foo (is (= (println 1) (println 2) (println 3) (println 4) (println 5))))

jsabeaudry16:09:56

on clojure 1.10.1

Alex Miller (Clojure team)16:09:53

$ clj
Clojure 1.10.1
user=> (require '[clojure.test :refer :all])
nil
user=> (deftest foo (is (= (println 1) (println 2) (println 3) (println 4) (println 5))))
#'user/foo
user=> (foo)
1
2
3
4
5
nil
user=> (foo)
1
2
3
4
5
nil

jsabeaudry16:09:21

(foo)
2
3
4
5
1

ghadi16:09:56

what development environment are you using?

dpsutton16:09:39

there's a testing plugin that adds an assert-expr for = that makes it ensure it has multiple forms. forgot what its called

💡 4
dpsutton16:09:47

but that's what i would expect

jsabeaudry16:09:48

@alexmiller Ok yes it works from cli

gerred16:09:51

@jsabeaudry781 can you be more specific? lol I just noticed Calva doesn't do printlns at all when using the run test harness, but has the same output when I evaluate directly.

dpsutton16:09:06

its humane-test-output that i'm thinking of

ghadi16:09:14

Does CIDER/nREPL not guarantee stdout order?

gerred16:09:27

socket repl, as expected, works just fine.

jsabeaudry16:09:19

I’m digging in my plugins, I have under 10 should be pretty quick

dpsutton16:09:00

sequential when running cider's testing commands and invoking the test directly in the repl (under nrepl)

jsabeaudry16:09:46

Is there a way to list enabled plugins?

noisesmith18:09:55

ironically it's another plugin

jsabeaudry16:09:09

I think I removed everything but cider-nrepl but I’d like to confirm I didn’t forget some place

pez16:09:18

Calva (so cider-nrepl):

REPL connected.
user=> (clojure-version)
"1.10.1"
user=> (require '[clojure.test :refer :all])
nil
user=> (deftest foo (is (= (println 1) (println 2) (println 3) (println 4) (println 5))))
#'user/foo
user=> (foo)
1
2
3
4
5
nil
user=> (foo)
1
2
3
4
5
nil
user=> 

gerred16:09:58

@pez odd...I had @jsabeaudry781’s output one time, then another time after jack-in I'm getting the same 🙀

gerred16:09:15

it's not like its halloween

pez16:09:49

What did you mean by when using the test harness?

gerred16:09:52

sorry, harness was a misspeak (actively writing tests right now...)

gerred16:09:59

so Calva: Run <N> Test commands.

gerred16:09:25

moving to #calva-dev 🙂

👍 4
dpsutton18:09:17

@jsabeaudry781 did you find the culprit?

jsabeaudry18:09:57

Nope getting back to it now, had to tend to other stuff

parens 4
ghadi18:09:22

M-x nrepl-toggle-message-logging
then look at the *nrepl-messages* buffer

ghadi18:09:33

might be a protocol-level problem with nREPL

jsabeaudry18:09:20

(-->
  id         "28"
  op         "info"
  session    "fe90d4ec-0faa-4e6c-a5a1-f4ca347efd3f"
  time-stamp "2019-09-23 14:18:37.911936000"
  ns         "foo"
  symbol     "foo/foo2"
)
(<--
  id         "28"
  session    "fe90d4ec-0faa-4e6c-a5a1-f4ca347efd3f"
  time-stamp "2019-09-23 14:18:38.508446000"
  column     1
  file       "..."
  line       7
  name       "foo2"
  ns         "foo"
  status     ("done")
)
(-->
  id         "29"
  op         "test"
  session    "fe90d4ec-0faa-4e6c-a5a1-f4ca347efd3f"
  time-stamp "2019-09-23 14:18:38.528316000"
  load?      "true"
  ns         "foo"
  tests      ("foo2")
)
(<--
  id         "24"
  session    "fe90d4ec-0faa-4e6c-a5a1-f4ca347efd3f"
  time-stamp "2019-09-23 14:18:38.681178000"
  out        "2
"
)
(<--
  id         "24"
  session    "fe90d4ec-0faa-4e6c-a5a1-f4ca347efd3f"
  time-stamp "2019-09-23 14:18:38.686466000"
  out        "3
"
)
(<--
  id         "24"
  session    "fe90d4ec-0faa-4e6c-a5a1-f4ca347efd3f"
  time-stamp "2019-09-23 14:18:38.691242000"
  out        "4
"
)
(<--
  id         "24"
  session    "fe90d4ec-0faa-4e6c-a5a1-f4ca347efd3f"
  time-stamp "2019-09-23 14:18:38.695911000"
  out        "5
"
)
(<--
  id         "24"
  session    "fe90d4ec-0faa-4e6c-a5a1-f4ca347efd3f"
  time-stamp "2019-09-23 14:18:38.700735000"
  out        "1
"
)
(<--
  id         "29"
  session    "fe90d4ec-0faa-4e6c-a5a1-f4ca347efd3f"
  time-stamp "2019-09-23 14:18:38.705696000"
  gen-input  nil
  results    (dict ...)
  summary    (dict ...)
  testing-ns "foo"

ghadi18:09:46

So nREPL is delivering stdout in the wrong order

ghadi18:09:59

So nREPL is delivering stdout in the wrong order

jsabeaudry18:09:38

What gives you this impression?

jsabeaudry18:09:46

timestamps match the order

ghadi18:09:08

the order should be 1 2 3 4 5

ghadi18:09:22

and it's receiving 2 3 4 5 1

ghadi18:09:40

and the editor prints it out 2 3 4 5 1

hiredman18:09:40

the 1 message is sent last, so if you assume that code is being executed in the correct order, then the clear indication is the messages are in the incorrect order

hiredman18:09:45

I haven't really been following but I still think it is super likely some plugin, either nrepl middleware, or to clojure.test extensions is screwing with things

jsabeaudry18:09:15

(deftest foo1
  (let [a (atom 0)]
    (is (= (swap! a inc) (swap! a inc) (swap! a inc)))))

hiredman18:09:35

what is that supposed to do?

ghadi18:09:09

evaluation is happening in the correct order -- it's just printing I think

jsabeaudry18:09:09

just showing that execution is incorrect confirming that some extensions is screwing with something

hiredman18:09:46

@ghadi the = in the is form may not be clojure.core/=

jsabeaudry18:09:06

if you change = for > then you see order is correct

hiredman18:09:10

the is macro has that multimethod extension thing based on the first of its argument

ghadi18:09:52

yeah when I macroexpanded it it was the ordinary =

ghadi18:09:00

didn't realize it's open like that

hiredman18:09:36

(get-method assert-exp '=) might help you figure out which library is screwing with it

hiredman18:09:03

alternatively if you use the fully namespaced form, clojure.core/= it will bypass the extension for =, unless someone also extend assert-expr for clojure.core/=, which I dunno, if someone was careless enough to break evaluation order I doubt that were careful enough to catch namespaced symbols

jsabeaudry18:09:29

I think it might also be cider’s handle-retest-op because it only happens from 2nd execution

hiredman18:09:27

so it is cider breaking it, but not at the nrepl protocol level

hiredman18:09:49

and they do extend the namespaced symbol as well 😞

jsabeaudry18:09:48

I’ll work on a patch for cider

jsabeaudry19:09:35

Let me know if you see possible improvements

ghadi18:09:59

So nREPL is delivering stdout in the wrong order

vlaaad19:09:09

(and (zero? a) (zero? b)) or (= 0 a b)?

noisesmith19:09:59

how about (every? zero? [a b])

noisesmith19:09:39

the = 0 version fails on 0.0 (might not matter in your case)

noisesmith19:09:21

there's (== 0 a b) which addresses that though

Lennart Buit19:09:37

huh, there is an exact integer representation of zero in floating point… ah okay

noisesmith19:09:53

yeah, = is never true between float and fixed

vlaaad19:09:58

good point about = and ==, although in my case I know for sure I operate on longs

noisesmith19:09:50

== works as expected for -0.0 as well

andy.fingerhut19:09:56

There are exact integer representations of all integers from about -2^53 to +2^53 in the double type, I learned a month or so ago.

Lennart Buit19:09:29

that is because there is a 53 bits mantissa ^^

andy.fingerhut19:09:40

Which I think is why JavaScript isn't completely insane to use 64-bit doubles as its default numeric type.

noisesmith19:09:09

yeah, I learned that 53 bit trivia in the context of JS

Lennart Buit19:09:37

yeah, I learned it from JS, then I looked back at university and remembered about the format of floats

Lennart Buit19:09:30

and because there is a sign bit, and you can fix the exponent on 1, you have 53 bits of integers positive and negative

andy.fingerhut19:09:32

There is not one, but 2 exact integer representations of zero in IEEE 754 floating point 🙂

Lennart Buit19:09:07

yeah, no 2s complement there

Lennart Buit19:09:37

floats are somewhat evil and elegant at the same time

noisesmith19:09:38

like so many things in cs generally :D

andy.fingerhut19:09:55

Tools with no sharp edges or warning points often make weak tools.

Lennart Buit19:09:19

words of wisdom ^^!

henrik21:09:45

You’ll like Rust then. I had a small headache dealing with floats in Rust land, coming from a far more lenient place. For example, they are unsortable (by default), because they may be NaN. This is IEEE approved as I understand it. You think you can just assume that 2.0 is greater than 1.0, you silly goose? Not around here, it ain’t.

henrik21:09:57

They’re also unhashable, so no using them as keys in a map.

andy.fingerhut21:09:24

No "guaranteed-not-a-NaN" subset that is comparable and hashable?

andy.fingerhut21:09:59

2.0 is greater than 1.0, but there is no total order over all IEEE floats if NaN is allowed.

henrik21:09:07

No, this is all true to their actual representation, as I understand it, and it’s your job to work out the limitations and safety in your program.

henrik21:09:34

The Rust PoV is that we’re all coddled and worse off for having someone else impose compromises over the reality of them.

andy.fingerhut21:09:00

The examples you cite sound like they could be examples of trying to prevent you from shooting yourself in the foot, aren't they?

henrik21:09:54

That’s very much it, you have to explicitly agree to shoot yourself in the foot, or define a safe subset.

henrik21:09:34

Were Clojure to do the same, we would not be allowed floats as keys in maps.

andy.fingerhut21:09:16

well, would you grant that some people might use floats as keys in maps and shoot themselves in the foot because of a lack of understanding of the properties of floats?

henrik21:09:46

That’s bound to happen.

andy.fingerhut21:09:52

The Rust approach sounds reasonable to me. Here are your shackles. You may break them if you want, but then it's on you to deal with the freedom given.

andy.fingerhut21:09:35

But if you are staying awake while breaking them, you should be thinking to ask why it was there in the first place, and presumably there are some docs explaining why.

henrik21:09:41

That would break the EDN “anything can be a key or a value” though.

andy.fingerhut21:09:21

Using NaN as a key in a map is a bad idea in Clojure, though. One of those ways to shoot yourself in the foot.

andy.fingerhut21:09:22

I'm not arguing for changes to Clojure here -- I have written my fair share of doc pages explaining where the sharp corners are, and how to avoid them. I should probably learn more about Rust, to learn more about their approach. Sounds interesting.

henrik21:09:35

Right, and in Rust, unless you can somehow guarantee at compile time that there never will be a NaN, it’s a no thank you.

henrik21:09:08

You may know that it will never happen, but the compiler doesn’t know that.

andy.fingerhut21:09:00

Sounds like an opportunity for someone to define a NaN-free subset of floats that compilers don't have to go to extraordinary lengths to preserve (someone may already have done such a thing, and I haven't heard about it)

henrik21:09:16

I like Rust, it’s got some nice things going for it. Shame about all the syntax, but hey, that’s ALGOL for you.

henrik21:09:16

That exists. There’s a crate you can pull in that has a different set of compromises (you’re allowed no NaNs)

henrik21:09:05

Oh, apparently there’s this one as well. Defines NaN as equal to NaN to get around it. https://crates.io/crates/fraction

andy.fingerhut21:09:28

Sounds like a potential performance impact, depending upon the implementation technique. Huh.

henrik21:09:51

Yeah possibly. Might be acceptable in some circumstances, for some programs, I suppose. Either way, you’re forced to choose, which is all they want in the first place.

henrik21:09:11

There are a lot of things in Rust that speaks to the sensibilities of someone coming from Clojure. Like, if you’re sharing a value, you’re going to share a constant. If you’re mutating it, you’re not also sharing it. You want to “share” it and also mutate, you have to make a copy.

noisesmith19:09:00

(so easy to forget negative zero)

dpsutton22:09:37

related to the testing issue above: is this a bug? it seems you have to redef tests for the new multimethod entry for assert-expr '= to take effect?

dpsutton22:09:55

the problem being: CIDER doesn't load middleware until a request comes in requiring it. The testing overrides here are brought in after the deftest are eval'ed, so that even after loading the middleware the defmethod has no effect until the tests are redefed. seems quite strange

hiredman22:09:08

assert-expr is basically a macro

hiredman22:09:28

so any changes to it are backed in at compile time, and you have to recompile to get hem

hiredman22:09:52

is is a macro, it calls assert-expr, and expands to the result

hiredman22:09:05

so baked in at compiled time just like any other macro expansion

dpsutton22:09:36

ah thanks. the assert-expr is called at macrotime and expanded rather than at run-time.