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?

Michael Fiano00: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

Michael Fiano00: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

Michael Fiano00: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

Michael Fiano00: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

Michael Fiano00: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

Michael Fiano00:03:59

Interesting, will do

Michael Fiano00:03:09

@dpsutton You just confused me ha

dpsutton00:03:20

what about?

Michael Fiano00:03:42

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

Michael Fiano00: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))

Michael Fiano00:03:07

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

Michael Fiano00: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

Michael Fiano00:03:16

Right, there's a TODO 🙂

Michael Fiano00:03:36

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

Michael Fiano00: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

Michael Fiano00:03:59

with a null pointer excpetion

dpsutton00:03:04

the jvm lurks 🙂

Michael Fiano00: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

Michael Fiano00:03:25

Thanks. One minute.

Michael Fiano00: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

Michael Fiano00:03:14

Same gist link is updated

dpsutton00:03:02

is it possible all of the rooms overlap?

dpsutton00:03:08

that would return an unmodified stage

Michael Fiano00:03:28

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

Michael Fiano00:03:19

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

Michael Fiano00: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

Michael Fiano00: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

Michael Fiano00:03:27

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

Michael Fiano01:03:38

@dpsutton Is boot instead of lein okay?

Michael Fiano01: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

Michael Fiano01: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

Michael Fiano01:03:52

I don't even have that file...

Michael Fiano01:03:58

Can you pull the latest fix and retry?

Michael Fiano01:03:07

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

Michael Fiano01:03:42

I pushed that fix to the build file too

Michael Fiano01:03:51

Everything should work for you now

dpsutton01:03:21

perfect i'm up and running

Michael Fiano01: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

Michael Fiano01:03:39

Hmm. What version of JVM and Clojure?

dpsutton01:03:15

complaining about ident

Michael Fiano01:03:04

I'm not sure what ident is

Michael Fiano01: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?

Michael Fiano01: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.

Michael Fiano01:03:03

I also tried latest Clojure 1.10 alpha

Michael Fiano02: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

Michael Fiano02:03:17

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

Michael Fiano02:03:21

Not the one in build.boot

Michael Fiano02:03:51

But yeah, that would be a problem considering spec was added in 1.9 🙂

Michael Fiano02: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

Michael Fiano02:03:13

Yeah @U04V70XH6 warned me about this when he got me to switch from lein. Only reason I remember 🙂

Michael Fiano02:03:58

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

Michael Fiano02: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?

Michael Fiano02: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

Michael Fiano02: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

Michael Fiano02:03:45

Let me explain...

Michael Fiano02:03:18

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

Michael Fiano02: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

Michael Fiano02:03:13

Does that make sense?

dpsutton02:03:17

yeah i think so

dpsutton02:03:37

we want to reduce over the cells collection.

Michael Fiano02: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?

Michael Fiano02: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

Michael Fiano02:03:38

I'm trying to understand it 🙂

Michael Fiano02:03:33

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

Michael Fiano02: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

Michael Fiano02: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

Michael Fiano02: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

Michael Fiano02:03:08

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

Michael Fiano02:03:13

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

dpsutton02:03:37

yeah. the terminology isn't firm in my head

Michael Fiano02: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

Michael Fiano02: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}

Michael Fiano02:03:34

I still need the doseq's though

Michael Fiano02: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

Michael Fiano02: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

Michael Fiano02: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

Michael Fiano02: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

Michael Fiano02: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.

Michael Fiano02:03:35

and a room does not have a list of cells

Michael Fiano02:03:59

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

Michael Fiano02: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}]

Michael Fiano02:03:13

That list is iteratively built BY this function

dpsutton02:03:16

you have the list of rooms right there in rooms

Michael Fiano02:03:48

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

Michael Fiano02:03:05

and only for N rooms

Michael Fiano02: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

Michael Fiano02:03:09

Ok are you looking at the file?

Michael Fiano02: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

Michael Fiano03: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

Michael Fiano03: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

Michael Fiano03:03:05

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

Michael Fiano03: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.

Michael Fiano03:03:35

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

Michael Fiano03: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

Michael Fiano03: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

Michael Fiano03: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

Michael Fiano03: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

Michael Fiano03: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

Michael Fiano03:03:44

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

Michael Fiano03: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.

Michael Fiano03:03:55

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

Michael Fiano08: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

Michael Fiano13: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

Michael Fiano13:03:54

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

Michael Fiano13: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.

Michael Fiano13:03:57

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

Michael Fiano13: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

Michael Fiano13: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?

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

Michael Fiano13:03:29

yeah. i see. late night coding eror.

Michael Fiano13:03:44

Also conj is not the right operation

Michael Fiano13:03:56

I need to keep the order of the original cells

Michael Fiano13: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})))))

Michael Fiano13: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.

Michael Fiano13:03:28

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

Michael Fiano13:03:42

Also there is a big problem with that code

Michael Fiano14: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

Michael Fiano14: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

Michael Fiano14: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

Michael Fiano14: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

Michael Fiano14: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)

Michael Fiano14: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

Michael Fiano14:03:18

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

dpsutton14:03:47

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

dpsutton14:03:50

¯\(ツ)

Michael Fiano14: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}}

Michael Fiano14: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

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

justinlee00:03:09

ah right. thanks!

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

Russ Olsen12: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."

👍 1
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”

Michael Fiano05:03:59

Are sets implemented as linked lists?

Michael Fiano07: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

Michael Fiano12: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

Russ Olsen13: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.

Russ Olsen13: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 @U9H7B8P7X! I've just realize that conj and cons params order are different lol

Russ Olsen13: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?

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.

Michael Fiano19: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...

🚀 11
bubblebobble 5
parrot 8
👏 3
👍 8
❤️ 2