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?

Nicki_Vance00:12:45

I draw my guidance from Clojure Brave & True, there are some data structure examples in there. I'm curious why you use keywords for the names of your columns :my-column? Why not a string? I find it harder to read keywords as values.

athomasoriginal00:12:22

In this instance, the value is just an example. The question is more around the bigger idea of manipulating data. I just whipped up a quick example 🙂

athomasoriginal00:12:59

Clojure for the brave and true is also a great suggestion, but at this point my questions have gone a little beyond that particular piece of literature 😞

jaide01: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

👍 4
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?"

jaide04:12:08

Dunno if this will be helpful to anyone else but created a macro to make it easier to document lessons when writing clojure files to try examples and solve exercises from a book. http://cl.ly/255446dfa01f The idea is the file\lesson can be executed and you see the lesson topic, notes, the code, and evaluation results.

👍 8
felipebarros05:12:02

I really like your idea and your editor also looks great XD I've been using org-mode to achieve a somewhat similar effect 🙂

nikola09:12:23

I see you're using Atom, did you get autocomplete working?

jaide15:12:23

@anantpaatra oh cool, that seems like a great solution too

jaide15:12:33

@nikola auto complete is working for me. Should I paste my profiles.clj?

petrusbr21:12:15

@jayzawrotny I really enjoyed your idea. Would you mind sharing your macros (I'm beginning Clojure now). Thanks!

nikola22:12:39

and you have [proto-repl "0.3.1" as a dependency in project.clj, right?

jaide22:12:39

I just have proto-repl as a plugin in my profiles.clj

jaide22:12:03

@UDU7HGK8T

{:user {:plugins [[cider/cider-nrepl "0.18.0"]
                  [proto-repl "0.3.1"]
                  [com.jakemccrary/lein-test-refresh "0.23.0"]]
        :dependencies [[nrepl "0.5.3"]]
        ; :resource-paths ["/Users/jay/Tools/REBL/REBL.jar"]

nikola22:12:21

thanks, let me give it a go

nikola22:12:17

no effect...

jaide00:12:57

@UEXSQM0HX Thanks. I’m refining some features such as formatting evaluation results once that’s done like tonight or tomorrow I’ll release it as library you can just add to your deps.edn or project.clj.

jaide10:12:01

@UEXSQM0HX Here’s the source of the macro. I’m still working on the refactoring before publishing the library but you can copy the file and use it https://github.com/jayzawrotny/book-report/blob/master/src/book_report/core.clj

petrusbr13:12:16

Thank you very much, @jayzawrotny!

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?

jaide04: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.

Alex Miller (Clojure team)06: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)

Alex Miller (Clojure team)06: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.

Alex Miller (Clojure team)06:12:37

there is no “parse”

Alex Miller (Clojure team)06:12:47

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

Alex Miller (Clojure team)06:12:03

quote means read but don’t eval

💯 4
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!

🍺 4