Fork me on GitHub
#clojure
<
2018-09-08
>
grav09:09:55

What’s an easy way to read-in the contents of an edn-file with a hash-map, keeping the order?

grav09:09:07

The best I have currently, is to read it as a string, and replace the { and } with [ and ] … which is not pretty

mavbozo09:09:38

the content of your edn file like this {:a 1, :b 2} ?

grav09:09:26

Yes, exactly

mavbozo09:09:35

and what is the expected result?

grav09:09:55

[[:a 1] [:b 2]] for instance

grav09:09:59

Anything really, that is ordered.

mavbozo09:09:10

and you want to keep the order say if the edn file is {:a 1, :c 3, :b 2}

mavbozo09:09:41

you want the result to be [[:a 1] [:b 2] [:c 3]]?

grav09:09:37

Hashmaps aren’t ordered, so directly read-string’ing it will only work up to a certain size, and even that is only luck, and might change with Clojure 1.x.

mavbozo09:09:51

something like this works (into (sorted-map) (clojure.edn/read-string (slurp "test.edn")))

grav09:09:57

But (clojure.edn/read-string (slurp "test.edn")) will be evaluated first, and at that point you have no guarantee of the order?

Timo Freiberg09:09:10

grav, you want to keep the order from the file, right?

mavbozo09:09:10

yes, but you can order the hash-map by the key using sorted-map

Timo Freiberg09:09:43

you should have read mavbozo's example a bit more carefully 😉

grav09:09:04

Ah, yes. Sorry @mavbozo I want to keep the order in the file 🙂

mavbozo09:09:20

ah ok, so if the content of your file is this {:a 1, :c 3, :b 2} then the result is [[:a 1] [:c 3] [:b 2]]?

grav09:09:46

Yes, precisely 🙂 This time I read your example more closely 🙂

schmee09:09:51

no way to do that, hash maps are not ordered

grav09:09:58

I guess what I need is something that parses the edn file as a structure and not a hashmap, so that I can extract the order

schmee09:09:12

indeed 🙂

Timo Freiberg09:09:33

you could just replace {} with [] and then call partition 2 on the vectors

Timo Freiberg09:09:55

hopefully you don't have any vectors in there you don't want to partition

mavbozo09:09:52

@grav for me this is interesting problem. what problem domain are you working on that requires you to maintain the order of the hash-map in the edn file? I'm assuming you don't have any control on the edn file creation

grav09:09:03

@timo.freiberg It does contain vectors, but only replacing the first { and last } ought to solve that.

grav09:09:23

@mavbozo I often run into hashmaps (either in code or in edn files) where the order was thought to matter by whoever created the map (by accident), so easily extracting the order would be pretty nice. I guess the best solution is, as @timo.freiberg suggests, to perceive it as a string and then “fix” the data-structure.

Timo Freiberg10:09:49

i hope this isn't an XY problem 🙂

grav10:09:54

Ah, reading wikipedia, I think I know what you mean 😉

grav10:09:51

Thinking of it again, I guess there is a less specific problem hidden in there, namely parsing a string as a list of symbols. I’m wondering if there’s anything in Clojure that will help me there.

genRaiy10:09:19

I am experimenting with the prepl and since there is not a prepl channel I’ll ask here

genRaiy10:09:58

by default the prepl uses pr-str to output values

genRaiy10:09:30

but this results in odd things like strings getting extra quotes after evaluation

genRaiy10:09:09

i.e. "foo" becomes "\"foo\""

genRaiy10:09:20

and this is awkward when rendering

genRaiy10:09:43

does anyone have tips / advice on dealing with this?

genRaiy10:09:42

I know I can replace pr-str with another function but want to avoid - if possible - writing a whole bunch of code if there is already a simple, known solution 🙂

genRaiy10:09:53

in other words, rather than replacing pr-str with my own code, is there something that exists to save me the work? Yes I’m lazy!

Space Guy10:09:36

@grav 'rewrite-clj' parses files as individual tokens (as well as whitespace), here's what I managed to get:

Space Guy10:09:38

(ns test-rewrite
  (:require [rewrite-clj.parser :as p]
            [rewrite-clj.node :as n]
            [rewrite-clj.zip :as z]))

(def pp (p/parse-string "{:a 1 :c 2 :b 3 :e [1 2 3]}"))
pp
;; #rewrite_clj.node.seq.SeqNode{ ... }


(n/child-sexprs pp)
;; (:a 1 :c 2 :b 3 :e [1 2 3])

(map vec (partition 2 (n/child-sexprs pp)))
;; ([:a 1] [:c 2] [:b 3] [:e [1 2 3]])

(vec (map vec (partition 2 (n/child-sexprs pp))))
;; [[:a 1] [:c 2] [:b 3] [:e [1 2 3]]]

Space Guy10:09:33

There's probably an easier way to read tokens with a normal edn reader instead, though

grav10:09:39

@spacemods Ah, very nice! I actually went ahead and wrote one that just mangles strings: https://gist.github.com/grav/a89bef351683ce4ded2b36615548ca30 But handling tokens seems more sane, at least in the general case 🙂

deliciousowl10:09:16

Interesting question from a C# friend of mine about game dev: In Clojure, how do you handle multiple, seperate enemies which all have the same default variables without OOP/inheritance?

andrea.crotti11:09:06

just a base map and a merge @coinedtalk?

deliciousowl11:09:48

(def game-state (atom {})) ?

deliciousowl11:09:01

and enemies {}

deliciousowl11:09:14

is that what you mean?

andrea.crotti11:09:29

(def common-traits
  {:height 100
   :strength 200})

(def gen-traits
  [custom]
  (merge common-traits custom))

deliciousowl11:09:36

hmm, and something like this would make sense?

{:type "Monster" {:type "Plant-based" {:type "Green"}}}

deliciousowl11:09:26

lets say I have established a monster template with your code, how do I spawn one? Create a protocol for handling movement,etc? or

andrea.crotti11:09:59

if these things are orthogonal probably {:types [:monster :plant-based :green]}

andrea.crotti11:09:48

and well it depends on what you are doing, here we were just talking about how to set some attributes to a monster

andrea.crotti11:09:17

the actual game logic depend on what are you programming for, but the idea is that you should leave the side effects as much as possible out of the way

andrea.crotti11:09:29

so avoid thinking about atoms too much

deliciousowl12:09:23

many thanks, I'm mainly wondering what the next step would be to spawning unique monsters and running movement methods on them. looking at defprotocol... defmethod etc

andrea.crotti12:09:53

defmulti and the corresponding defmethod sounds like a good choice

andrea.crotti12:09:17

but keep in mind that it's nothing magic, you could the same dispatching with a map that you write yourself

(def action {:monster (fn [_] (attack!))...)

deliciousowl12:09:38

hmm, how would that work if there's multiple monsters

andrea.crotti12:09:01

that's just an example of dispatching a function based on a keyword

andrea.crotti12:09:08

it wasn't really realistic code

deliciousowl12:09:46

got it, I'll go with defmulti and defmethod 🙂

pbaille13:09:38

does anyone tried to implement scheme's 'syntax-rules' for clojure?

andy.fingerhut13:09:56

First hit in Google search for "clojure syntax-rules" shows this Github repo: https://github.com/qbg/syntax-rules I haven't used it, and don't know whether it is considered complete or mostly-bug-free.

pbaille13:09:41

thank you, @andy.fingerhut , i'm aware of this project, but it seems to be quite different from scheme's syntax-rules (i have not really dug into it)

andy.fingerhut13:09:23

Not sure which aspect you are looking for, but with clojure.spec created after that lib was, one aspect of Clojure macros that is (arguably) improved is better specification and checking of the syntax of macros.

andy.fingerhut13:09:48

It doesn't change how macros are implemented, though.

pbaille13:09:11

I agree that spec can help with macros, but i really like the conciseness of syntax-rules

pbaille13:09:42

it would be nice to have for a certain class of macros

pbaille13:09:49

it is not so easy to implement (for me)

pbaille13:09:40

and it would make some crazy scheme easier to port (like http://okmij.org/ftp/Scheme/macros.html#ck-macros)

dangercoder15:09:44

Are refs prefered when building a queue? I need to make sure 2x items are not getting into the same batch.

dangercoder15:09:41

i am currently using an agent since I want to do things when items are added to the vector (using add-watch)

johnj20:09:24

ConcurrentLinkedQueue

dangercoder20:09:01

I have a solution using that one. I would use this solution if I didn't have to be able to cancel and remove items from the queue.

dangercoder20:09:12

Im leaning more towards a core.async solution right now