Fork me on GitHub
#beginners
<
2019-02-12
>
ScArcher04:02:20

When you map a function over something what is returned? is it a collection of return data?

chrisulloa04:02:41

A lazy sequence

👍 5
chrisulloa04:02:09

But yes a collection of that function applied over the data, just not realized until you ask for it.

ScArcher04:02:14

I see. It worked the way I thought it should. I was trying to then map println which resulted in nil. Instead I had to apply println.

chrisulloa04:02:09

Did you do that in the repl?

ScArcher04:02:29

I'm using Calva and it's truncating the results in the REPL for some reason.

chrisulloa04:02:36

repl will realize your map function for you

ScArcher04:02:40

It would have worked if I had just typed it into the REPL

ScArcher04:02:45

Would have been more obvious.

ScArcher04:02:24

Trying a simple project in Clojure. I've literally been reading about it for years, but never done anything with it.

chrisulloa04:02:41

Are you enjoying it so far?

ScArcher04:02:04

So far so good. There are definitely some nice libraries to make what I'm trying to do easy.

chrisulloa04:02:27

That’s good! Calva looks like a neat tool I will have to check it out sometime.

ScArcher04:02:28

I had to rework my approach so it would be REPL friendly. I was nesting my functions in a way that made it difficult to work with at first.

chrisulloa04:02:33

Ah yeah, thread macros ->> -> make nesting readable

ScArcher04:02:57

Yep I was trying to do too much in a given function too.

ScArcher04:02:04

I haven't used the thread macros yet.

chrisulloa04:02:26

working with thread macros lets you think about composability of your code

ScArcher04:02:04

I'm looking to store a map in an atom, then use clojure.data.diff to see when it changes. If it changes, I want to update the value in the atom, then trigger an action.

ScArcher04:02:22

Does this sound reasonable? Is there a "best practice" for this type of thing?

seancorfield04:02:29

@scott.archer You can add a watcher to an atom so that function is called when it changes.

ScArcher04:02:31

I don't really mean "monitor" the atom, but call a function to get the differences.

ScArcher04:02:18

It sounds like a watcher could work to trigger the event based only on the change. Would that be a good way to go about this?

seancorfield04:02:55

Then you could check the old and new state and see if it changed in a way that you need to trigger your event.

seancorfield04:02:21

But if your "check" also updates the value in the atom, you might get into a loop 🙂

seancorfield04:02:50

I'm not really sure what you mean by "If it changes, I want to update the value in the atom"

ScArcher04:02:28

I'm scraping a website looking for product changes, then I want to generate a text message if something has changed.

ScArcher04:02:38

It's not a complex use case, just using it to learn.

seancorfield04:02:19

Yeah, I think this would work for you then. The watcher function would check whether old state = new state and, if not, generate the message.

ScArcher04:02:03

Yep it's worth trying. Thanks for the help. The last time I tried to get started on a clojure project, I got some stuff working, but it wasn't done the clojure way and it didn't feel any different than java.

ScArcher04:02:14

I'm trying to do a better job working through this.

seancorfield04:02:35

Getting into the functional mindset is (at least) half of the battle if you're coming from Java, I think.

ScArcher04:02:08

It is and I think writing code that decomposes well so that the REPL is useful seems really important too.

seancorfield04:02:33

Aye, the REPL is a game-changer, once you get into the flow with it (see Stu Halloway's talks "REPL-Driven Development" and "Running With Scissors").

seancorfield04:02:53

Key advice: never type directly into a REPL. Type into a (source) file instead, and evaluate each form as you type it. You can put REPL experiments inside a (comment ..) form to stop them affecting the source file when it is loaded. And keep them there as notes on what worked (and perhaps what didn't).

ScArcher04:02:28

I actually saw the (comment trick today and I'm using it. It works great!

ScArcher04:02:27

@seancorfield do you use Calva by any chance?

seancorfield04:02:45

I have used it occasionally. Mostly I use Atom and Chlorine.

ScArcher04:02:53

It keeps truncating my results for some reason I thought you might be using it.

ScArcher04:02:58

in the REPL.

seancorfield04:02:51

It's fairly standard in editor integrations to prevent crashing/locking up when you accidentally print very large data structures.

seancorfield04:02:14

If it shows ... in the output, it may be clickable to expand the data some more.

ScArcher04:02:21

I'll check it out. Thanks!

seancorfield04:02:46

There's a #calva-dev channel in case you need to ask detailed Qs about it.

agigao12:02:55

Hi there, I'm trying to update the specific entry in a map upon predicate and at the end I get a map with only the updated entry (the rest of entries eventually turn into nil):

(update data :sms (fn [coll]
                    (map #(when (= id (:id %))
                            (conj % {:sent? true}))
                         coll)))

Alex12:02:30

use if, not when

Alex12:02:28

is sms a map?

agigao12:02:58

yup, it is

agigao12:02:54

oops, yeah, got it! thank you!

Alex12:02:00

You can use (map #(merge % (when (= 1 (:id %)) {:sent? true})) [{:sent? false :id 2} {:sent? false :id 1}])

Alex12:02:04

If you don’t want to use if

Alex12:02:27

you can in this case also use assoc instead of conj, personally conj is confusing for me in this instance

Alex12:02:48

but im also a beginner 😄

agigao13:02:12

dunno, conj works fine in my mental model right now xD

agigao13:02:15

Thank you Alex!

mathpunk21:02:49

argh, time---

mathpunk21:02:57

Observe:

(let [given-t "1549913529.537"
          t 1549913529537]
      (java.util.Date. t))

mathpunk21:02:30

I derived t by multiplying by 1000, or more to the point, by editing out the "s and the . :face_with_rolling_eyes:

mathpunk21:02:37

of course I would rather not do that

mathpunk21:02:32

But this is no good:

(let [given-t "1549913529.537"
          t (Double. given-t)]
      (java.util.Date. t))

mathpunk21:02:02

nor is this:

(let [given-t "1549913529.537"
          t (Integer. (* 1000 (Double. given-t)))]
      (java.util.Date. t))

mathpunk21:02:37

I think that integer might be too big for Integer?

dpsutton21:02:24

(-> "1549913529.537" (str/replace "." "") (Long/parseLong) (java.util.Date.))

mathpunk21:02:26

I've just constructed my first ever BigInteger.... which java.util.Date has also never heard of

mathpunk21:02:43

oh a Long is not a Double

mathpunk21:02:55

I sort of thought Long, Double, and Float were all the same name for the same idea

Lennart Buit21:02:32

Float/Double are formats for values with decimals

Lennart Buit21:02:12

They are neat (and terrible) in that they can represent a very wide range of values between absolutely tiny (e.g. 0.00000000000001) and massive in 32/64 bits respectively

Lennart Buit21:02:38

they do this by trading off accuracy for range. So some values you can device are not representable in float/double

czem16:02:05

0.1 + 0.2 = 0.30000000000000004 https://floating-point-gui.de/

dpsutton21:02:06

not sure what the constraints of the initial string are, but if its precision is always 3 you can just delete the decimal to multiply by 1000 and then parse it?

mathpunk21:02:25

I think that is the case --- this is super-prototypey so it's okay if it explodes later

noisesmith21:02:52

@mathpunk I'm sure BigInteger is fine here, but I can think of very few cases I'd use Integer over Long

noisesmith21:02:00

similar with Float vs. Double

noisesmith21:02:06

prefer the 64 bit types

mathpunk21:02:09

Long is a big 64-bit integer, and Double is a 64-bit float?

Lennart Buit21:02:58

(in Clojure, longs can store values between -(2^63 + 1) — 2^63, so they are signed)

andy.fingerhut22:02:20

[-2^63, 2^63-1] inclusive (sorry can't resist pointing out off by one bugs)

Lennart Buit22:02:35

I actually googled it even, but assumed the wrong value :’)

dpsutton22:02:20

i remember hearing a neat thing. The minimum value in ranges like this is not representable as a literal

dpsutton22:02:53

ie if the range is [-16, 15] you can't represent -16 as a literal of that type. you get type promoted

andy.fingerhut22:02:33

You mean, in Java programs?

dpsutton22:02:50

yes. but i think its common across most languages due to the way things are parsed

dpsutton22:02:58

presumably the same thing in clojure

Lennart Buit22:02:14

I know of rust that did strange things with non-inclusive ranges for all byte values

Lennart Buit22:02:34

like if you said 0…256 non-inclusive

dpsutton22:02:10

its because -X is parsed as unary operator negation on X. and the minimum is usually larger in absolute value terms than the maximum. so in the range [-16, 15] -16 is (negate 16) and the 16 there is too large for your type so you get type promotion

andy.fingerhut22:02:34

user=> Long/MIN_VALUE
-9223372036854775808
user=> (type -9223372036854775808)
java.lang.Long

5
Lennart Buit22:02:36

and (type -9223372036854775809)?

Lennart Buit22:02:24

ah bigint as expected

andy.fingerhut22:02:52

First time I have seen Slack's animation for deleting a message. Cool!

dpsutton22:02:02

java does not have this problem apparently. (type (- 9223372036854775808)) is BigInt

dpsutton22:02:17

perhaps this was only in C# or C++?

noisesmith22:02:59

user=> (type (unchecked-subtract 0 9223372036854775808))
clojure.lang.BigInt

noisesmith22:02:20

of course this is because 9223372036854775808 is already bigint

dpsutton22:02:04

yes that number is too large for Long. There are some languages that don't read -9223372036854775808 (a valid Long) as this number but as negating 9223372036854775808 (a positive number) which is too large for longs

dpsutton22:02:07

and java does have this defect (it seems)

HelloWorld.java:5: error: integer number too large: -9223372036854775808
        long x = -9223372036854775808;
                  ^
1 error

dpsutton22:02:14

public class HelloWorld{

     public static void main(String []args){
        System.out.println("Hello World");
        long x = -9223372036854775808;
     }
}

dpsutton22:02:35

clojure has a better long parser than java

noisesmith22:02:36

another way clojure is better than java :D

Lennart Buit22:02:53

- is a unary operator in Java right

dpsutton22:02:59

I assumed this would make its way into clojure

Lennart Buit22:02:11

so, it first parses 9223372036854775808 as long, but that isn’t a long

noisesmith22:02:41

yeah - and since clojure doesn't need to use java for parsing, I'm not surprised that bug is fixed

dpsutton22:02:11

i just thought that was really cool when i learned it. a value is not expressable as a literal

Lennart Buit22:02:33

yeah, but it makes sense if you think about how that would be structured in a grammar

Lennart Buit22:02:08

class Main {
  public static void main(String[] args) {
    System.out.println(- - 6);
  }
}
Yeah, unary operator

dpsutton22:02:41

it looks like the compiler uses a regex to match integers. but it looks like it always returns a bigInteger. so i'm a little confused

Lennart Buit22:02:13

can you link the source ^^ kinda intrigued

noisesmith22:02:36

assuming LispReader.java

👍 5
Lennart Buit22:02:31

Cool, thank you both!

dpsutton22:02:59

I have almost no experience in the compiler but I want to change that. Noisesmith is well versed in it. I assume a few patches as well?

dpsutton22:02:17

(if not significant development)

noisesmith22:02:32

oh no, just a lot of inquisitive poking :D

Lennart Buit22:02:18

but yeah, the pattern on line 69 contains -/`+`, so the value is parsed whole instead of being negated later on

Lennart Buit22:02:26

(as is the case in the Java grammar)

dpsutton22:02:43

ah no, it reads everything into biginteger and then tries to go down to longs if possible

mathpunk22:02:11

I have never seen this time format before --- 0211/133208.940471. That's MMDD/??????.???

mathpunk22:02:55

gotta be it

andy.fingerhut22:02:11

133208 is more than the number of seconds in one day, so not sure what that is intended to be.

andy.fingerhut22:02:22

Where did you find that?

mathpunk22:02:23

this is coming out of a ChromeDriver log.... that precision is quite a claim

mathpunk22:02:42

maybe it's not a timestamp, but heck if I know what it is

mathpunk22:02:13

thanks, @andy.fingerhut, i was hoping someone would have recognition on whether this was quite likely ridiculous

andy.fingerhut22:02:30

Seconds since the process started, maybe?

mathpunk22:02:56

maybe.... I think I'm going to put this down and back away

mathpunk22:02:09

I have many other events of interest with sane timestamps

andy.fingerhut22:02:28

Logging tends to proliferate time representations.

noisesmith22:02:07

s/time representations.//

john22:02:51

maybe js/window.performance.now()?

john22:02:11

I guess you can get higher resolution timestamps out of there