Fork me on GitHub
#beginners
<
2018-12-21
>
sova-soars-the-sora00:12:38

Hmmm. well, right now i'm just using assoc to store some session variables. user-email, login-time, and the auth-key i'm assigning

sova-soars-the-sora00:12:02

but if i were to conditionally associate some elements, what's the ~idiomatic way to use cond-> ?

Nicki_Vance00:12:25

Hi folks, I'm a little late to the advent of code game 🙂 but here goes. I made this little function to check if a number has been seen, if it has, return it, if not, add it to the set of numbers seen. As you can see, my function works as expected in the first example. When I pass the function into reduce, why do I get an error that a Long is being cast as a function? I expect `#{0} to be cast as a function.

Nicki_Vance00:12:04

(I have a fix for this but I want to understand the error.)

sova-soars-the-sora00:12:33

what does (if (seen new)) mean?

Nicki_Vance00:12:42

seen is the first argument to the function, in this case #{0 1}, new is the second, 1`.

sova-soars-the-sora00:12:01

What are we testing for?

Nicki_Vance00:12:21

(#{0 1} 1) checks if 1 exists in the set #{0 1}

Nicki_Vance00:12:01

similar to how ({:key "val"} :key) returns the value of the key in the map

Nicki_Vance00:12:17

to be more specific, these functions don't just "check", they return the value if found

Nicki_Vance00:12:25

give it a try 🙂

Nicki_Vance00:12:39

yeah, its super cool

Nicki_Vance00:12:04

there are just a few data structure that can be used as functions

sova-soars-the-sora00:12:23

Your error, casting Long to fxn...

sova-soars-the-sora00:12:29

i don't get it, you're invoking with a set?

sova-soars-the-sora00:12:47

if you were putting (1 #{0 1}) somehow, then that would make sense as an error

sova-soars-the-sora00:12:38

Oh I see, the expected behavior is something like "doesn't contain 1, conj 1, does contain 1, return 1, doesn't contain 2, conj 2..."

seancorfield00:12:25

Your function is returning different types of things, but reduce will keep applying to whatever you return.

seancorfield00:12:49

So when you return just new, that will get used as the next seen -- but it will be an int, not a set.

sova-soars-the-sora00:12:59

reduce is hammering away at that returned 1 ?

sova-soars-the-sora00:12:45

interesting... so maybe change that new into a (println new) or conj into some other book-keeping set? anyway, not the op.

sova-soars-the-sora00:12:57

very cool! learned something very handy about reduce just there.

seancorfield00:12:14

seen is bound to #{0} on the first invocation and new is 1 so the first result is #{0 1} ...

seancorfield00:12:35

... which becomes seen for the next invocation with new as the second 1 in that sequence ...

seancorfield00:12:54

... which has been seen so it returns new (`1`) ...

sova-soars-the-sora00:12:21

what's the reduce-friendly way to write it?

seancorfield00:12:22

... which becomes seen for the third invocation with new as 2 ... and then it blows up.

sova-soars-the-sora00:12:44

i've crafted many a landmine in my day ;D

seancorfield00:12:39

It depends what exactly the problem requires. I'm not clear on that from @nicki’s initial post...

Nicki_Vance00:12:04

ah, I see, thanks @seancorfield ! I was assuming reduce would stop. Now it all makes sense why reduced exists!

Nicki_Vance00:12:11

which is what worked for me

seancorfield00:12:37

Yes, if all you're trying to do is find the first repeated number, (reduced new) will work.

seancorfield00:12:03

(not sure why you're starting with 0 in the seen set of values, rather than an empty set tho'?)

Nicki_Vance00:12:18

ah, good catch, i think it's a carryover from an earlier version of the function where I needed [0] instead of 0. An empty set works and would be better because it wouldn't raise questions. 😉

athomasoriginal00:12:52

I find myself fighting to come up with elegant ways to transform nested collections like this:

[{:table 
  :columns
  [{:column :my-column
    :values [{:from 1 :to 5}]
             {:from 2 :to 6}]}
   {:column :my-other-column
    :values [{:from 5 :to 12}
             {:from 9 :to 13}]}]
 ...
]
This seems like a reasonable way to organize my structure, but when it comes time to be able to do things like - get all column names associated to each :columns key: e.g. (:my-column :my-other-column) - filter out unwanted column names from :columns and then update :columns to only include the columns I want e.g. :columns [{:column :my-other-column :values [...]] and so on, I find the solutions become gnarly. Part of this is me still wrapping my head around the Clojure standard library, but I wonder if perhaps another aspect is the above data structure could be better structured? I suppose the question is a big one, but when clojurists are defining their structures, what kind of questions do you ask yourself to ensure you are creating structures that will work with you and not against you? Further, maybe there are some books / articles people could suggest to improve this part of my Clojure game?

Eccentric J01:12:35

@tkjone Well you could build some functions around get-in, update-in, and assoc-in but you can also reach for https://github.com/nathanmarz/specter

👍 1
seancorfield01:12:51

@tkjone If your column names are known to be unique, use a map-by-column-name instead of a vector-of-column-descriptions

seancorfield01:12:11

So

...
:columns 
{:my-column {:values [...]}
 :my-other-column {:values [...]}}
...

seancorfield01:12:13

(-> data :columns keys) will give you the list of column names when you need it, the other filtering, getting, and updating becomes easier.

seancorfield02:12:09

If you need ordering, keep a separate vector of just the column names in order:

:column-order [:first-col :second-col ...]
:columns {...}

athomasoriginal02:12:56

Good points! This is along the lines of what I wanted to do: re-structure based on how I will use the DS, but I am always wavering on coupling semantics v. what is best for me when transforming. Not that the alternatives you presented aren’t conveying semantics.

athomasoriginal02:12:09

In terms of specing something like

:columns 
{:my-column {:values [...]}
 :my-other-column {:values [...]}}
is it possible to do this because the keys are always changing?

sova-soars-the-sora02:12:52

Hi, I'm subtracting two timestamps and keep getting 1

sova-soars-the-sora02:12:07

(defn is-good-auth-key [auth-key user-email login-time]
  (let [now (quot (System/currentTimeMillis) 1000)
        phase (- now login-time)
        shift 1300000 ;1.3 mil seconds = 2 weeks

        valid? (< phase shift)]
      (println now login-time phase)
      (password/check (str user-email login-time) auth-key)))

sova-soars-the-sora02:12:18

why does phase always print out as 1? o_O

sova-soars-the-sora02:12:31

i'm trying to assure that the login time was within a particular range

sova-soars-the-sora02:12:37

Addition works just fine O.O

sova-soars-the-sora03:12:36

nevermind, it was showing 1 and -1 because I was asking "hey what's the difference between right now and right now?"

andy.fingerhut04:12:25

@jayzawrotny Out of curiosity, is that text copied from Chapter 5 of some book you are going through, and if so, which book?

Eccentric J04:12:12

I was paraphrasing in the notes but it’s from Chapter 5 of Clojure for the Brave and True https://www.braveclojure.com/functional-programming/ “Pure Functions Are Referentially Transparent”

dbsgtk05:12:51

I just upgraded to 1.10, and somehow blew it. https://pastebin.com/hYCB8mKi

jumar05:12:47

It might be some issue with Java 9, although not sure why. The canAccess method has been added in that release: https://docs.oracle.com/javase/9/docs/api/java/lang/reflect/AccessibleObject.html#canAccess-java.lang.Object It seems that your jdk 9 installation is quite old - maybe you could try to upgrade.

seancorfield06:12:26

Yeah, I think I would suggest updating to the actual JDK 9 release rather than testing against an internal/prerelease build like that.

felipebarros05:12:42

Why does ((last '(inc inc inc)) 2) returns nil instead of 3?

chrisulloa06:12:20

I don’t have a good answer but looking at it:

user=> (type (last '(inc inc inc)))
clojure.lang.Symbol
user=> (type (last [inc inc inc]))
clojure.core$inc
user=> ((eval (last '(inc inc inc))) 2)
3
https://clojure.org/reference/evaluation

chrisulloa06:12:01

Which seems equivalent to doing 'inc which also generates a Symbol rather then the function itself.

seancorfield06:12:46

@anantpaatra That's equivalent to ('inc 2) -- note the quote -- which is then try "call" a symbol (not a function) and symbols can be invoked and they look themselves up in their argument -- in other words, it's the same as (get 2 'inc) which is why you get nil.

seancorfield06:12:17

('inc 2 :not-found) will produce :not-found because it's like (get 2 'inc :not-found)

felipebarros06:12:36

hmm, even ((last [inc inc inc]) 2) returns nil.

seancorfield06:12:58

That returns 3 for me

seancorfield06:12:09

user=> ((last [inc inc inc]) 2)
3

chrisulloa06:12:20

Returns 3 for me too

felipebarros06:12:26

Oh, yeah, my mistake.

felipebarros06:12:03

I did ((last (vec '(inc inc inc))) 2)

seancorfield06:12:39

Yup, you still have symbols there, not functions.

seancorfield06:12:55

You could do ((last (list inc inc inc)) 2)

seancorfield06:12:22

The quote ' prevents evaluation of the expression.

alexmiller06:12:30

in general, the evaluation model in Clojure is that everything evaluates as itself except for lists (which invoke the first element with the rest as args) and symbols (which are replaced with what they refer to)

alexmiller06:12:20

quote prevents evaluation so is primarily used on those two special cases (symbols and lists)

felipebarros06:12:24

I thought that a first parse on something quoted would unquote the result.

alexmiller06:12:37

there is no “parse”

alexmiller06:12:47

there’s read (text -> clojure data) and eval

alexmiller06:12:03

quote means read but don’t eval

💯 1
felipebarros06:12:07

That makes total sense now..

nikola09:12:10

@shin I'm in the same boat as you, doing http://adventofcode.com is very fulfilling and I'm learning a lot in the process

andersmurphy16:12:49

Where do people keep there stest/check checks for spec? How do you run them? do you embed them in your unit test or run them separately?

jumar17:12:00

I think I only have written two such tests but I put them inside normal deftest

Denis G16:12:27

any clojure RPC libs to recommend? slacker? https://github.com/sunng87/slacker

bartuka21:12:33

hi ppl, I’m starting with reframe. I created an api using compojure and I want to reach out my endpoints after some event in the front-end. How can I reach my endpoint from cljs side?

jstaab23:12:52

I haven't used re-frame, but I'd imagine you'd want to make requests during phase 3 "effect handling". As far as pulling it off, you can call XMLHttpRequest or fetch directly (depending on your target browser), or you can use a clojure client, like http-kit: http://www.http-kit.org/client.html

bartuka00:12:55

I found the cljs-ajax library that makes requests to server-side too, however my question is more related to the fact that my API (all my endpoints) is inside the same project. I have a clj/ folder with a compojure project and a cljs/ folder with the reframe files. I still have to reach the endpoints from this API in the same way as if it’s a completely external API.

bartuka00:12:24

I thought I would be “integrating” this two world together and would be possible to reach the endpoints in a different fashion.

jstaab00:12:58

Gotcha, I'm not sure if there's any best practice in clojure for tightly integrating the two, but the way I generally do it is to treat the api as an external api, except I serve my html template from the domain (whether you use a reverse proxy or just serve it alongside your api resources is up to you). That way you can make requests to '/api/whatever` rather than . It also prevents you having to deal with CORS which is a minor pain.

jstaab00:12:50

Since you're making requests client side, it's all about path resolution from the outside rather than any directory structure goings on

bartuka01:12:24

Got it! Thanks!

🍺 1