Fork me on GitHub
#beginners
<
2018-03-26
>
noisesmith00:03:09

@mfiano: there's a good lib for immutable randoms in clojure

dpsutton00:03:40

but there's no need for immutability of the rng i don't think right?

mfiano00:03:44

@noisesmith I specifically needed a portably seedable PRNG with very particular number generation functions (so I wrote my own)

noisesmith00:03:25

@dpsutton the specific use case of the linked library is to be able to concisely replicate generative test inputs that failed

mfiano00:03:25

That is the same stage should be generated from the same seed...that part needs to be deterministic because maps will be saved as the seed

dpsutton00:03:11

that sounds tough to do across platforms.

dpsutton00:03:22

i'm assuming you've got this in CL and scheme

mfiano00:03:28

Python and CL. I never used a Scheme before

dpsutton00:03:27

well it looks like a really cool project and can't wait to see it

mfiano00:03:00

Thank you. I've only been working on it for a couple days. I keep having to stop to read clojure docs being new as I am ๐Ÿ™‚

dpsutton00:03:31

ok. reading it in common lisp, you mutate the stage instance. remember in clojure to just thread that stage map around. as an argument and then return it with either stuff added to it or not

mfiano00:03:52

Yeah, I get that. Infact...my ultimate goal is to store a list of all changes made to the stage so that I can play back the generation as an animation in Quil or something

dpsutton00:03:58

so make your place-rooms function return (update stage :rooms conj room)

dpsutton00:03:22

look into reductions

dpsutton00:03:39

it makes an infinite lazy list out of the intermediate stages of a reduce

mfiano00:03:59

Interesting, will do

mfiano00:03:09

@dpsutton You just confused me ha

dpsutton00:03:20

what about?

mfiano00:03:42

I thought I was making a new function add-room-to-stage that does that with a single room.

mfiano00:03:09

Oh was that a typo pluralization?

dpsutton00:03:47

what typo? I don't follow

dpsutton00:03:25

oh that was just pseudocode. i'm big on simple functions and descriptive names. for you it would be

(defn place-room
  [stage room]
  (update stage :rooms conj room))

mfiano00:03:07

place-room is the function that iterates over the rooms cells and marks them as no longer being walls

mfiano00:03:17

As you can see by the nested doseq

dpsutton00:03:56

oh. i saw that and saw it didn't do anything. the nested doseq doesn't return anything

mfiano00:03:16

Right, there's a TODO ๐Ÿ™‚

mfiano00:03:36

So with all these changes I don't get any output anymore

mfiano00:03:45

Stack trace of root exception is empty;

bronsa00:03:00

it's an optimization of the jvm

bronsa00:03:09

if you disable it you'll get the stacktracs

bronsa00:03:15

-XX:-OmitStackTraceInFastThrow

mfiano00:03:59

with a null pointer excpetion

dpsutton00:03:04

the jvm lurks ๐Ÿ™‚

mfiano00:03:48

Seems to be a problem with that loop. commenting it out doesn't error

dpsutton00:03:49

if you want to post the loop here in this thread we can talk about it if you want

mfiano00:03:25

Thanks. One minute.

mfiano00:03:20

Ok I got it to compile but I don't know if it is doing anything with the rooms. I don't see them in the stage structure.

dpsutton00:03:12

Make sure you're returning the updated version not the original version. Remember no mutation

mfiano00:03:14

Same gist link is updated

mfiano00:03:20

I think I am?

dpsutton00:03:02

is it possible all of the rooms overlap?

dpsutton00:03:08

that would return an unmodified stage

mfiano00:03:28

No I print them out and they are small and do not overlap

mfiano00:03:19

Actually if I change the last line to (do (println new-stage) new-stage) I do see them added!

mfiano00:03:32

But this poses a problem

dpsutton00:03:39

this seems to work for me

dpsutton00:03:44

(add-rooms {:rooms []
            :width 14
            :height 20
            :room-extent 4
            :density 0.8})
{:rooms [#fizzbuzz.core.Room{:x1 8, :y1 14, :x2 11, :y2 17} #fizzbuzz.core.Room{:x1 5, :y1 16, :x2 8, :y2 19} #fizzbuzz.core.Room{:x1 4, :y1 8, :x2 7, :y2 11} #fizzbuzz.core.Room{:x1 7, :y1 4, :x2 10, :y2 8} #fizzbuzz.core.Room{:x1 1, :y1 7, :x2 4, :y2 11} #fizzbuzz.core.Room{:x1 1, :y1 3, :x2 4, :y2 7}], :width 14, :height 20, :room-extent 4, :density 0.8}

dpsutton00:03:58

what's the probmem?

dpsutton00:03:25

i'm not sure what reasonable values for height and width are but there you go

dpsutton00:03:58

it would be nice if you would def an empty stage in there

mfiano00:03:03

Ok actually this seems to work now. I updated my gist. The only thing left to do is do the carving in place-room. That will take some thought to be immutable

mfiano00:03:27

I suppose I could push the whole project. It isn't very large.

mfiano00:03:44

One minute

mfiano01:03:38

@dpsutton Is boot instead of lein okay?

mfiano01:03:45

I don't have a lein project.clj

dpsutton01:03:28

we'll make it work

dpsutton01:03:35

just tell me how to crank it up

dpsutton01:03:54

its empty right now

dpsutton01:03:32

ok. got it cloned. forgot i didn't re install boot on this laptop

mfiano01:03:49

Oh ok. When you get that going you can eval (mfiano.crawler.stage/make-stage {:width 49 :height 49}) as an example. There are other parameters too, but that is the bare minimum

dpsutton01:03:31

java.nio.file.NoSuchFileException: resources file: "resources" clojure.lang.ExceptionInfo: resources line: 5

dpsutton01:03:38

i'm getting some errors

mfiano01:03:52

I don't even have that file...

mfiano01:03:58

Can you pull the latest fix and retry?

mfiano01:03:07

Oh "resources" should be an empty directory in the root of the project. Seems boot creates that

mfiano01:03:42

I pushed that fix to the build file too

mfiano01:03:51

Everything should work for you now

dpsutton01:03:21

perfect i'm up and running

mfiano01:03:59

Nice. So that will actually print the stage out too, which should be solid walls until those rooms are 'carved' out.

dpsutton01:03:00

your specs don't seem to be compiling for me

mfiano01:03:39

Hmm. What version of JVM and Clojure?

dpsutton01:03:15

complaining about ident

mfiano01:03:04

I'm not sure what ident is

mfiano01:03:13

JVM and CLJ are 1.9?

dpsutton01:03:00

not sure about jvm version. hope that doesn't matter

dpsutton01:03:07

i need to step away for dinner. be back in 30?

mfiano01:03:34

I'm on Clojure 1.9 and JVM 1.8 and I can't reproduce. That's ok. Take your time. I'll be here.

mfiano01:03:03

I also tried latest Clojure 1.10 alpha

mfiano02:03:28

I've been searching all over and I don't see where your error comes from. Do you have more info or were you able to get past it?

dpsutton02:03:34

for some reason its cranking up into clojure 1.8 even if i specify 1.9. i don't know why

mfiano02:03:55

Oh I know why

mfiano02:03:17

Boot uses the Clojure version specified in your global properties file.

mfiano02:03:21

Not the one in build.boot

mfiano02:03:51

But yeah, that would be a problem considering spec was added in 1.9 ๐Ÿ™‚

mfiano02:03:12

you should have a boot.properties file in your dotfiles

dpsutton02:03:49

yeah i found it. pretty unintuitive

dpsutton02:03:11

ok. its working now

mfiano02:03:13

Yeah @ warned me about this when he got me to switch from lein. Only reason I remember ๐Ÿ™‚

mfiano02:03:58

So what i need to do is somehow, modify the cells of the room in place-room.

mfiano02:03:30

Where that TODO is, I want to modify the features set of each cell of that room.

dpsutton02:03:00

ok. can you tell me in words what its supposed to do?

mfiano02:03:27

Sure. place-room is supposed to be iterating over all the cells of the room, and adding the keyword :room to the :features #{} set of each cell's hashmap

mfiano02:03:08

A cell is a hashmap, and a room contains many of these. I need to modify a particular key of each cell of the room to include this keyword in that set

dpsutton02:03:30

ok. so we need to map over a list of rooms and update each's :features entry to include :room?

dpsutton02:03:29

ok. well the doseq doesn't seem right to me. we need something that we want to modify and we need to update it

mfiano02:03:45

Let me explain...

mfiano02:03:18

The stage hashmap contains a :cells key which is a vector of cells (also hashmaps themselves).

mfiano02:03:04

each cell object has a :features key that is a set that needs a keyword added. The room just contains cells, but it's the stage which needs modifying

mfiano02:03:13

Does that make sense?

dpsutton02:03:17

yeah i think so

dpsutton02:03:37

we want to reduce over the cells collection.

mfiano02:03:57

Ok. I'm not very familiar with reduce. It's rarely used in CL

dpsutton02:03:59

(defn place-room [{:keys [width height rooms] :as stage} {:keys [x1 y1 x2 y2] :as room}] (let [updated-rooms (reduce (fn [acc room] ;;whatever ) [] rooms)]) (assoc stage :rooms updated-rooms))

dpsutton02:03:07

CL uses foldl maybe?

mfiano02:03:32

No, CL has reduce, but I've only used it like once in my 10 years of using that language exclusively ๐Ÿ™‚

dpsutton02:03:50

well think of it as recursion.

dpsutton02:03:13

it'll keep recursing with two arguments. the value you are building up and each entry in a collection

dpsutton02:03:28

so we have all the rooms and we'll keep calling this function and build up the collection of rooms again

dpsutton02:03:58

(reduce conj #{} [:a :b :c]) is an example

mfiano02:03:38

I'm trying to understand it ๐Ÿ™‚

mfiano02:03:33

Ok I see. There are 2 versions, with a starting value and not

mfiano02:03:53

So your example would be the same as (conj (conj (conj #{} :a) :b) :c)

dpsutton02:03:21

yeah. should always go with a starting value if you can

dpsutton02:03:27

yes exactly

mfiano02:03:45

So what should I reduce to?

dpsutton02:03:17

]so we'll build up our rooms. starting with an empty vector [] and loop over all the rooms. and if we are interested we'll conj :room into its features set

mfiano02:03:18

I guess I use update in the reducing function to change the cell's features?

dpsutton02:03:47

and we'll start with a collection of rooms and reduce it to a new collection of rooms

mfiano02:03:08

You know, I've tried to understand reduce a few times over the years, and your explanation just clicked

mfiano02:03:13

build up our rooms? don't you mean cells?

dpsutton02:03:37

yeah. the terminology isn't firm in my head

mfiano02:03:44

Also, what is the acc param?

dpsutton02:03:23

in the reduce above, it would be the empty set, the set containing just a and then the set containing a and b

dpsutton02:03:47

we're accumulating those values into a set

mfiano02:03:00

I see. Let me try something and see if I understand

dpsutton02:03:27

(reduce conj #{} [:a ๐Ÿ˜› :c]) ;; => (conj #{} :a) -> #{:a} ;; => (conj #{:a} :b) -> #{:a :b} ;; => (conj #{:a :b} :c) -> #{:a :b}

mfiano02:03:34

I still need the doseq's though

mfiano02:03:07

I only have a room object. I need to get all that room object's cells

dpsutton02:03:58

crank it out. ask if you have any questions

mfiano02:03:23

Yeah that changes things. I'm not sure how to do that. I have a single room that only has the 2 coordinates of a rectangle. I need to somehow loop to collect all of its cells before I can reduce

dpsutton02:03:00

you have access to all of the rooms though, right?

dpsutton02:03:20

clojure works best when you think of how to make a new thing, rather than identify a few and modify them

mfiano02:03:22

At that time, no. place-room only places a single room

dpsutton02:03:35

but it places it into a stage which has all the rooms

mfiano02:03:47

But at that time the stage may not have them all

dpsutton02:03:48

so you can iterate over all of them and "modify" the ones that are impacted

dpsutton02:03:18

i'm not understanding. i thought stage held all of the information

mfiano02:03:13

Remember that add-rooms function you helped me with earlier? That is calling this function, place-room, iteratively. This function is placing a single room into the stage.

mfiano02:03:35

and a room does not have a list of cells

mfiano02:03:59

it only has 2 points representing the rectangle in order to find its cells

mfiano02:03:36

So 1) All rooms are not in the stage in this function, except the last iteration, 2) I need to somehow collect the cells of the room that it's working on before I can reduce

dpsutton02:03:43

the stage has the list though? :rooms

dpsutton02:03:10

[{:keys [width height rooms] :as stage} {:keys [x1 y1 x2 y2] :as room}]

mfiano02:03:13

That list is iteratively built BY this function

dpsutton02:03:16

you have the list of rooms right there in rooms

mfiano02:03:48

My whole point is that list doesn't exist until this function returns

mfiano02:03:05

and only for N rooms

mfiano02:03:32

Perhaps I'm not explaining myself well. Don;t worry about it ๐Ÿ™‚

dpsutton02:03:53

I need to somehow collect the cells of the room that it's working on before I can reduce what does this mean

dpsutton02:03:57

what rooms are you working on

mfiano02:03:09

Ok are you looking at the file?

mfiano02:03:23

The last function in that file is recuring over place-room. place-room is updating the stage with a single room each recurrence. in place-room where you are telling me to get a list of all rooms, it doesn't have that information

mfiano03:03:03

Besides, it's not rooms that I need. I need a nested loop to collect the cells of a room.

dpsutton03:03:10

ok. but remember, collecting things like that and then modifying them isn't a good way to work in clojure. because you can't mutate like that

dpsutton03:03:33

so if you collect a subset, i'm not sure how you would recreate your original data structure. you cant just push or setq on them

mfiano03:03:10

All a room is is x1, y1, x2, y2. I need to loop over that range of cells in the grid, in order to get cells that should be updated in the actual stage

mfiano03:03:05

I don't want to mutate. I want to return a new data structure with the changes somehow

mfiano03:03:35

That's what placing a room involves. Finding the cells of a room, and then changing those cells features.

dpsutton03:03:49

ok. so you want a function from grid -> grid.

mfiano03:03:35

Yes the stage (grid) is the only thing ever being updated in this algorithm

mfiano03:03:48

The rooms are just static metadata

dpsutton03:03:19

so i'm starting to understand a little bit more. and i've got a suggestion

mfiano03:03:53

Ok, I made a little bit of progress, but I'm stuck so I'm open to that suggestion.

dpsutton03:03:05

there's no need to render the room in the grid during this loop. just do them all after the room generation is done

dpsutton03:03:33

and you can take the list of rooms and transform that list into a list of all of the grid coordinates

dpsutton03:03:16

and then create a grid with those positions marked as room

mfiano03:03:38

I made this but I wasn't expecting it to return a list of lists:

(defn collect-room-cells
  [stage {:keys [x1 y1 x2 y2] :as room}]
  (for [x (range x1 x2)]
    (for [y (range y1 y2)]
      (cell/get-cell stage x y))))

dpsutton03:03:00

(let [{:keys [x1 y1 x2 y2]} (make-room {:width 64 :height 64 :room-extent 17})] (for [xcoord (range x1 y1) ycoord (range y1 y2)] [xcoord ycoord]))

dpsutton03:03:07

(let [{:keys [x1 y1 x2 y2]} (make-room {:width 64 :height 64 :room-extent 17})]
  (for [xcoord (range x1 y1)
        ycoord (range y1 y2)]
    [xcoord ycoord]))

dpsutton03:03:16

don't nest your fors

dpsutton03:03:15

so mapcat that over all of your rooms in grid creation and if that cell is in this list, mark it as room, else leave it empty

mfiano03:03:32

mapcat is a new one for me too. Going to have to look that up

dpsutton03:03:53

its just map and then concat

dpsutton03:03:08

so for each room we get a list of coordinates and we combine them into one big list

dpsutton03:03:36

turn that into a set for quick lookup. then on grid generation, if this "pixel" is in the list of room "pixels" mark it as such

mfiano03:03:30

This changes things. I have to re-read my CL code because it may happen that I don't even need to store the :rooms in the stage hashmap

mfiano03:03:44

I can just mark the cells and throw the list away possibly

mfiano03:03:44

Ok I just looked over my old code and I am going to make some changes. The rooms shouldn't be stored in the stage. It's a temporary list.

mfiano03:03:55

I'm going to try doing what you suggested too. Thanks.

mfiano08:03:16

I spent all night trying to do what you said. I got farther. I generated the big list of cells like you said. And I did an attempt at deriving a new grid with feature set of some cells changed based on this list. It still has problems as noted in this comment. I'm out of ideas if you want to take a look: https://github.com/mfiano/crawler/blob/master/src/mfiano/crawler/room.clj#L63-L65

mfiano13:03:16

@dpsutton Thanks a lot for all your help. I think I am going to abandon this project. There must be something I'm not getting with Clojure to continue working with it.

dpsutton13:03:31

aw it seems really cool

dpsutton13:03:54

i'm sure the issue of ending up with a list is easily solvable. probably conj-ing on a nil somewhere

mfiano13:03:54

I think a big problem is a chose a wrong data structure for the grid of cells

mfiano13:03:35

It's just a vector of cells in order. I don't know of a way to update only some of them and maintain the same order.

mfiano13:03:57

But I also expect there to be something rendered and there is not...it renders as all walls still.

mfiano13:03:06

So there must be something I don't get about clj

dpsutton13:03:12

that's the paradigm shift you need to change. you can't change things. you need to have information and given this information, how do i make a new thing

dpsutton13:03:59

so given all of the cells you have, given this grid, loop over all of its cells making a new grid. if the information tells you it should be a room, then mark the cell a room in the new collection

mfiano13:03:50

That's exactly what I did, but it's done wrongly because it conj's the new ones to the end, rather than putting them where they were.

dpsutton13:03:36

which function?

mfiano13:03:11

carve-cells

dpsutton13:03:45

so one thing i notice is that you never use the room-cells argument

dpsutton13:03:56

and you have the original stage passed in so its ignoring all of your work

dpsutton13:03:24

so if you notice all of those "stage" parameters are the same initial value. stage does not change

dpsutton13:03:28

it is immutable

mfiano13:03:29

yeah. i see. late night coding eror.

mfiano13:03:44

Also conj is not the right operation

mfiano13:03:56

I need to keep the order of the original cells

mfiano13:03:13

Ok, I see. That function purposefully is wrong in the sense that you pointed out. I wanted to just update the features of the original stage to see if something rendered, but it is still rendered as walls.

dpsutton13:03:05

(defn make-grid [] (let [stage {:width 64 :height 64 :density 0.6 :room-extent 10} rooms (collect-rooms stage) coords (set (mapcat (fn [{:keys [x1 y1 x2 y2]}] (for [xcoord (range x1 x2) ycoord (range y1 y2)] [xcoord ycoord])) rooms))] (for [x (range (:width stage)) y (range (:height stage))] (cell/->Cell x y true 0 0 (if (contains? coords [x y]) #{:room} #{:wall})))))

mfiano13:03:12

I am going to need to do something better than hashset literals. There will be times when I want to add some instead of replace like that.

mfiano13:03:28

That's why I wrote the add-features and remove-features functions

mfiano13:03:42

Also there is a big problem with that code

mfiano14:03:59

The rooms need to be placed AFTER the original cells are created...not create the cells from the room cell coords. The next part of the algorithm is to carve a maze around all the rooms, and apply different features depending on each cell's neighbors. THis whole generator is highly mutable

mfiano14:03:24

I'm not sure if it can be done immutably...and surely not reversing the operations like you just did

dpsutton14:03:58

(defn make-grid [] (let [stage {:width 8 :height 8 :density 0.6 :room-extent 4} grid (for [x (range (:width stage)) y (range (:height stage))] (cell/->Cell x y true 0 0 #{:wall})) rooms (collect-rooms stage) coords (set (mapcat (fn [{:keys [x1 y1 x2 y2]}] (for [xcoord (range x1 x2) ycoord (range y1 y2)] [xcoord ycoord])) rooms))] (reduce (fn [new-grid cell] (let [{:keys [x y]} cell] (conj new-grid (if (contains? coords [x y]) (-> cell (update :features conj :room) (update :features disj :wall)) cell)))) [] grid)))

dpsutton14:03:32

so here we take an initial grid, and loop over it updating cells if they are in the room collection, otherwise leaving them alone

dpsutton14:03:18

immutability can do everything that mutable can do. we just have to give instructions on how to create something new from something old

dpsutton14:03:03

the idea is we loop over the grid with information about which ones should be marked as a room. and as we are looping, we just add in the original or add in a new cell that is modified how we want it to be modified

mfiano14:03:12

I see. If I use my add-features and remove-features functions here that use clojure.set functions for difference and union, will that work without converting the set into a list again? I sort of need this later on

mfiano14:03:23

Those functions are in cell.clj

dpsutton14:03:49

yes it should

dpsutton14:03:05

although you should require clojure.set and then use them

mfiano14:03:38

At the moment I'm on a computer without my dev environment on a long car ride. When I get to my workstation later I'll try all your advice.

dpsutton14:03:52

here's your problem

dpsutton14:03:53

(clojure.set/union #{:a} '(:b :c)) (:a ๐Ÿ˜› :c)

mfiano14:03:56

I just want to say again how much I appreciate your time and explanations

dpsutton14:03:07

you are using the & operator to get a list and clojure set doesn't like that

dpsutton14:03:21

(clojure.set/union #{:a} (set '(:b :c))) #{:c ๐Ÿ˜› :a}

dpsutton14:03:34

so change this (defn add-features [cell & features] (update cell :features clojure.set/union features))

dpsutton14:03:41

(defn add-features [cell & features] (update cell :features clojure.set/union (set features)))

dpsutton14:03:48

to this. note the call to set on features

dpsutton14:03:39

and the great thing about a repl and small functions like this is you should call them individually to make sure they work when using them in a big pipelin

dpsutton14:03:00

yeah. clojure set deals with a garbage in garbage out philosophy

dpsutton14:03:16

if you give them malformed or non set type things they don't throw an error, they just do undefined behavior

mfiano14:03:18

I actually tested those functions in the repl and it didn't care they were lists...it was a set result

mfiano14:03:32

Oh undefined

dpsutton14:03:47

ah, it's because a list with one element is fine. a list with two elements is not

dpsutton14:03:50

ยฏ\(ใƒ„)/ยฏ

mfiano14:03:43

(defn add-features [cell & features] (update cell :features clojure.set/union features))
(add-features {:x 1 :y 2 :features #{:a :b :c}} :d :e :f)
{:x 1, :y 2, :features #{:e :c :b :d :f :a}}

mfiano14:03:54

Why is that the case then?

dpsutton14:03:21

don't know. maybe i'm wrong then

dpsutton15:03:16

i switched to personal message so we have more space

lee.justin.m00:03:40

merge seems to be a subset of the functionality of into per this example

cljs.user=> (merge {:a 1 :b 2 :c 3} {:b 9 :d 4})
{:a 1, :b 9, :c 3, :d 4}
cljs.user=> (into {:a 1 :b 2 :c 3} {:b 9 :d 4})
{:a 1, :b 9, :c 3, :d 4}
cljs.user=> 
Is there some advantage to merge that I am missing?

bronsa00:03:27

merge takes n maps

bronsa00:03:49

also you can (merge nil a-map) and get back a map, if you try that with into you get a list

lee.justin.m00:03:09

ah right. thanks!

gleiry.serrano01:03:29

Hello! I am new here. So I just want to ask this. Can I consider clojure a general purpose language? Can you suggest a problem set? I plan to use clojure for engineering stuff but first of all I want to have fun doing cool algorithms.

russ76712:03:56

At Cognitect we've used Clojure to implement games, large (and if I dare say) boring financial applications, lots of medical related stuff, imaging, educational software and more single page web apps than many programmers have had hot lunches. I also hear there is a database implemented in Clojure as well.

alexmiller01:03:59

yes, it is a general purpose language and people use it for anything you can imagine

andy.fingerhut02:03:23

Fun quote from about 20 years ago from Kent Pitman, attempting to counter the impression that Common Lisp was a language specialized for Artificial Intelligence applications: "Please don't assume Lisp is only useful for Animation and Graphics, AI, Bioinformatics, B2B and Ecommerce, Data Mining, EDA/Semiconductor applications, Expert Systems, Finance, Intelligent Agents, Knowledge Management, Mechanical CAD, Modeling and Simulation, Natural Language, Optimization, Research, Risk Analysis, Scheduling, Telecom, and Web Authoring just because these are the only things they happened to list."

andy.fingerhut02:03:44

I don't know if Clojure has already been used for all of those application areas already, but it certainly could be.

dpsutton02:03:33

We're building medical record and billing software with it :)

stardiviner02:03:07

Is there some Clojure web scraping, crawler framework can be suggested?

alexmiller04:03:18

there are a couple linked at https://www.clojure-toolbox.com/ under โ€œWebsite scrapingโ€

mfiano05:03:59

Are sets implemented as linked lists?

mfiano07:03:04

Right. I was wondering about their access time compared to lists and vectors for things like contains?

sundarj07:03:45

they're implemented as a special case of maps (with keys equal to values)

orestis09:03:00

Should have O(1) time, or is it log32(N) which quite close to constant? Or was that the vectors?

alexmiller12:03:47

sets are hashed and stored in a tree. access time for lookup via contains? is O(log [base 32] n). A tree with 32-way branching factor is very shallow and wide, so in most cases you wonโ€™t hit more than 1-2 branches).

max.forasteiro11:03:31

Hi guys! Anyone here already used compojure-api?

ikitommi12:03:42

@max.forasteiro ping. one of the authors here.

max.forasteiro12:03:32

thank god! haha So, i have a end point that receives a json with a person and then I save this person to the population (that is a atom and the save is a swap! to the atom)

max.forasteiro12:03:18

idk if the person is not coerced or my return definition is wrong

ikitommi12:03:19

what do you get when calling the endpoint?

max.forasteiro12:03:00

my code:

(POST "/person/new" []
        :return Person
        :body [p Person]
        :summary "Add person"
        (ok (swap! persons #(conj % p))))

max.forasteiro12:03:42

error:

{
  "errors": "(not (map? a-job_queues.handler$add_agent$fn__15061))"
}

max.forasteiro12:03:49

I think my mistake is on :return definition, but idk if the p is a Hash after coercion

ikitommi12:03:52

(POST "/person/new" []
   :return Person
   :body [p Person]
   :summary "Add person"
   (swap! persons conj p)
   (ok p))

ikitommi12:03:11

swap! returns the whole value.

max.forasteiro12:03:51

just one more question: can I put as much methods I want before send the ok response?

ikitommi12:03:42

yes. Itโ€™s wrapped in a do.

ikitommi12:03:16

in repl, you can call

(macroexpand-1 `(GET "/api" [] โ€ฆ.))
to get the generated source code.

max.forasteiro12:03:16

with a vector atom, how can I insert elements on the beginning and still has a vector?

max.forasteiro12:03:44

(def var1 (atom []))
(swap! var1 conj var2) ;insert at the end and is a vector
(swap! var1 cons var2) ;serialize all contents of var2 to vector and converts to list

mfiano12:03:44

conj inserts into a collection in an efficient way for the given collection. For lists, that means at the head, since the original list can just be pointed at in the tail of the new cons and the entire list does not have to be linearly searched in order to find the end. For vectors, this means growing it and inserting 1, instead of shifting the entire vector down one, also slow. For this you'd maybe want to take advantage of lazy sequences, and use (into [] ...).

max.forasteiro13:03:50

test.core=> (def var1 (atom []))
#'test.core/var1
test.core=> (swap! var1 conj {:foo "bar"})
[{:foo "bar"}]
test.core=> (swap! var1 cons {:bar "foo"})
([{:foo "bar"}] [:bar "foo"])

max.forasteiro13:03:39

the problem is: the cons call convert all to vector idk why

russ76713:03:23

The cons function gives you back a sequence. Clojure has lots of functions like this that take a collection, turn it into a sequence and then do their thing, returning a sequence. Long story short, the vec function will take a sequence and turn it into a vector.

russ76713:03:36

Oh and keep in mind that there are two completely separate things going on in your original example: The atom is just a mutable container for a value. I think the issue you are having is with vectors and sequences, where your vector happens to be stored in an atom.

max.forasteiro13:03:43

Thank you @! I've just realize that conj and cons params order are different lol

russ76713:03:05

Oh yes, that! You're welcome.

ikr13:03:40

I've been following the https://clojurescript.org/guides/quick-start and got stuck at the

clj --main cljs.main --compile hello-world.core --repl
step. I'm getting
$ clj --main cljs.main --compile locau.core --repl
Error building classpath. Failed to read artifact descriptor for org.clojure:clojurescript:jar:1.10.238
org.eclipse.aether.resolution.ArtifactDescriptorException: Failed to read artifact descriptor for org.clojure:clojurescript:jar:1.10.238
        at org.apache.maven.repository.internal.DefaultArtifactDescriptorReader.loadPom(DefaultArtifactDescriptorReader.java:276)
        at org.apache.maven.repository.internal.DefaultArtifactDescriptorReader.readArtifactDescriptor(DefaultArtifactDescriptorReader.java:192)
โ€ฆ
Caused by: org.eclipse.aether.resolution.ArtifactResolutionException: Could not transfer artifact org.clojure:clojurescript:pom:1.10.238 from/to central (): java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter mustbe non-empty
        at org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolve(DefaultArtifactResolver.java:422)
        at org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolveArtifacts(DefaultArtifactResolver.java:224)
Indeed, I don't see anything like org.clojure/clojurescript at https://repo1.maven.org/maven2/ What am I doing wrong?

ghadi14:03:30

@ikr java 9?

dnolen14:03:02

that might be it

ghadi14:03:51

Yeah there's an issue with a lot of jdk9 containers, they're missing CA certificates

dnolen14:03:17

though I have Java 9 as default and I havenโ€™t seen that one

ikr14:03:52

@ghadi @dnolen Alright. Will try with Java 8 now.

ghadi14:03:47

JDK 10 should work too

ikr14:03:00

@ghadi @dnolen Yay! Switching to Java 8 fixed it. Thank you!

ghadi14:03:57

Great. Can you share details of the broken environment? OS or container image @ikr

ikr14:03:48

It's openjdk-9-jdk on Debian Stretch, from https://packages.debian.org/stretch-backports/

ghadi14:03:09

Oracle vs OpenJDK

mathpunk17:03:40

I have a web page to test with WebDriver. I figured I'd serve that page with ring, but I can't figure out a handler to write so that my app only serves that static resource. Like for instance, lein-ring requires that I have a handler in my profile, but the simplest handler instances have a body. How can I just serve a static page?

mathpunk17:03:56

For the moment I'm having my WebDriver instance navigate to a file on my own filesystem. That doesn't seem right at all, though it will work as I develop other stuff.

mfiano19:03:10

This Slack is by far the friendliest programming community I've ever encountered in my many years coding. Not sure if this is Clojure in general, or Clojurians, but everyone here that has helped me over the last week or 2, I just want to say thank you. You know who you are. Hit my first milestone today thanks to a couple of you here. More learning tomorrow...