Fork me on GitHub
Alex Miller (Clojure team)00:10:20

I don't think that's supported in Free

Alex Miller (Clojure team)00:10:18

(but I could be wrong, I am not on the Datomic team and am not an expert)


@alexmiller thanks, I was wondering the same after reading the datomic docs on tuples


@iagwanderson Looks like Tuples were new in Datomic On-Prem 0.9.5927 and the most recent free version is 0.9.5703.21 -- but it looks like Datomic Pro Starter has (somewhat) replaced the free edition and it would include the latest features I think.


I don't know if I understood what you said about Datomic Pro replacing the free-edition.


I should be moving to use the pro-starter now?


From "Datomic Pro Starter Edition (new!) is now the best no-cost way to get started with Datomic for small production deployments."


That also shows the last release date for the free edition: 2019-06-28 -- ironically the same date as which refers to Datomic On-Prem 0.9.5927.


rsrsrs I see. I got the license already. The problem is only the expiration date


fortunately this is not a problem for me right now. But eventually it will be


I thought it was only a matter of getting just twelve months of updates -- and then needing a new Pro Starter license (for a different project)?


I had one that expired in 2018 and I could not use it again with the new version of datomic-pro released this year. Maybe I would got stuck with this 12+months of updates and didnt realized.


Ah, right. Then I guess you have to see if they release a new free version...?


I dont know the exact steps, I just got a new one with my companies emails ๐Ÿ˜•


Hello! Is there a way, a deep dive article for understanding internals of lazy sequences and building programs with lazy sequences?


Not so much about the internals, but I am reading the chapters covering sequences & laziness in "Programming Clojure" by Miller et al & it has clear examples and explanations.


@hendre.ani if you would like to see a few auto-generated figures of what the Java objects look like that are used to represent lazy sequences in Clojure, take a look here: . Those figures were generated using the library cljol:


That is only if you are interested in the internal implementation details. It does not tell you how to use them to write programs -- just about any book on programming Clojure will have some discussion about that.


Thanks! @andy.fingerhut. Iโ€™m reading Programming Clojure. I guess that is good enough for understanding the how part.


Note that most people use lazy sequences just fine without ever digging into how Clojure implements them (I had not, until I wrote the library that generates those figures)

๐Ÿ‘ 4

@andy.fingerhut That's very cool stuff! I've seen you mention cljol before but I hadn't looked at the diagrams...


Yep, I had fun making those -- figuring I would refer at least a few interested people to them later. The gallery was my way of saving stuff that I thought was interesting.


Yes, really great stuff. Thanks for sharing!


I didn't add it to the gallery yet, but the representation of some unbounded / infinite sequences are pretty interesting. IIRC, (repeat 5) is represented very memory-efficiently, with a single Java object pointing at itself, and the Long 5.


If I have a vector of maps, i.e., (def topics [{:topic-name "a"} {:topic-name "b"}]) and I need to pass each element of that vector (i.e., each map) into a function, but capture the eval/result of that function for later usage, what approach might I take. I can't use map since it's lazy (need eagerness) and doseq and it's kin eval to nil.


mapv is eager


fantastic - works beautifully! thanks @vlaaad ๐Ÿ™‚

Abhinav Sharma11:10:24

Hello Clojurians, Iโ€™ve been trying to transform a map so that the new map doesnโ€™t contain references to a specific value - but Iโ€™m really struggling with this for now. Any help or pointers are definitely appreciated.

(def people1 {:car/id      {1 {:car/id 1, :car/model "T-150"},
                             2 {:car/id 2, :car/model "Ferrari"},
                             3 {:car/id 3, :car/model "Mercedez"}},
               :person/id   {1 {:person/id     1,
                                :person/name   "Joe",
                                :person/spouse [:person/id 2],
                                :person/cars   [[:car/id 1] [:car/id 2]]},
                             2 {:person/id     2,
                                :person/name   "Dafny",
                                :person/spouse [:person/id 1],
                                :person/cars   [[:car/id 3]]}},
               :root/person [[:person/id 1] [:person/id 2]]})

The new map is completely free from [:person/id 1]
(def people2 {:car/id      {1 {:car/id 1, :car/model "T-150"},
                             2 {:car/id 2, :car/model "Ferrari"},
                             3 {:car/id 3, :car/model "Mercedez"}},
               :person/id   {2 {:person/id     2,
                                :person/name   "Dafny",
                                :person/spouse nil,
                                :person/cars   [[:car/id 3]]}},
               :root/person [[:person/id 2]]})


Is the shape of that map expected to be consistent? If it is, you can use something like (dissoc (:person/id people1) 1) and (filter #(not (= [:person/id 1] %)) people1) to clear out the references directly. It's more of a brute force approach but it'll definitely get the job done. If you can't depend on the shape of that map however, clojure.walk/postwalk might be of help to you. It's a depth first traversal that you can use to affect change or find paths to specific keys or values in a map. The last thing I'll point you to which I think may help is the clojure tree-seq function. It returns all of the nodes in a tree via a depth first walk. I use it often to find a key in a nested map so I'm sure you can adapt it to replace a key. Here's the find-key function I found a while back (like 2017) and have been using since:

(defn find-nested-key
  [m k]
  (->> (tree-seq map? vals m)
       (filter map?)
       (some k)))

Abhinav Sharma15:10:38

Hi @U0DHQ67U5, thanks for the pointers! ๐Ÿ‘ To answer your question, yes the depth of the map would be consistent for sure, however not the number of the keys or the number of values within each key. However, this tree-seq and find-nested-key definitely seems to be of use - let me try this out and circle back ๐Ÿ™‚

๐Ÿค™ 4

Can you provide more context to your question?


Not to me. You wanted a function that got you from people1 to people2, right? What was your solution?


I was replying to a question that now seems to be removed.


Is there a standard/best practice way to do configuration in clojure apps? i.e. how to handle configurations in multiple files (maybe a global and a project file?)


@donyorm There are multiple ways to do this. For example there's aero: which allows you to specify config based on env variables all in one file


+1 to aero


in a project I'm currently working in we're using


I use aero, really nice


The project I'm currently working on requires end users to configure it as well. Aero doesn't seem to really handle that, crispin might, have to read the readme a bit more carefully. What's generally considered the best way to do that?


"It depends."


I quite like Metabase's approach:

(defn config-str
  "Retrieve value for a single configuration key.  Accepts either a keyword or a string.

   We resolve properties from these places:

   1.  environment variables (ex: MB_DB_TYPE -> :mb-db-type)
   2.  jvm options (ex: -Dmb.db.type -> :mb-db-type)
   3.  hard coded `app-defaults`"


But maybe working at Metabase has biased me somewhat ๐Ÿ˜œ


Are there any decent guides for RDD? Like setting up a dev/ folder and dealing with creating files there to run/toy with your project there?


@decim I just have (comment ,,,) forms inside the main source of the project containing the "toy" code. Some folks have a single scratch file or one per month outside any projects that they use for experimentation.

๐Ÿ‘ 4

@seancorfield OK... I have seen that in code that I've read over. I suppose it is best to keep things simple


The simpler your process -- and your tooling -- the more likely you are to use it consistently on all projects and even when you're just experimenting.


I try to keep (at least) one REPL open at all times, with "all" the dependencies I need (at least, all of the stuff needed by our 30-or-so subprojects at work) so I almost never need to start a new REPL "just to experiment". I try to (almost) never type directly into a REPL -- always into a file so REPL "experiments" are kept somewhere. I try to code in very small steps: write code, eval into REPL, write code, eval into REPL. If I have any question in my mind about how some code might behave, I put it in a (comment ,,,) and eval it to see what happens. Focusing on the feedback loop really helps me.


Keeping things simple is the key so you can use the same workflow anywhere, with any project.

David Omar20:10:46 Last week I watched this talk following Sean's advice. At that second, he talks about the REPL and Rich Comment Blocks. He cites a previous talk about RDD (that I haven't watched). I've found useful wrapping things inside a do block inside the comment block.


@davidomarfch hmm, iโ€™ll take a look. Thanks


Yeah, both of Stu's talks on RDD are worth watching.


(I use Cognitect's REBL alongside my ediitor)

๐Ÿ‘ 4

Ok, subscribed to you as well. Cool.


(I don't publish new pieces very often!)