This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-05-24
Channels
- # adventofcode (11)
- # architecture (12)
- # beginners (132)
- # boot (19)
- # cider (26)
- # clojure (69)
- # clojure-dusseldorf (4)
- # clojure-gamedev (1)
- # clojure-italy (46)
- # clojure-nl (4)
- # clojure-serbia (1)
- # clojure-switzerland (2)
- # clojure-uk (91)
- # clojurescript (79)
- # css (4)
- # cursive (2)
- # datomic (16)
- # docs (9)
- # duct (20)
- # editors (94)
- # fulcro (15)
- # graphql (2)
- # hoplon (1)
- # instaparse (7)
- # jobs (3)
- # lein-figwheel (3)
- # leiningen (2)
- # lumo (40)
- # mount (35)
- # off-topic (19)
- # reagent (18)
- # reitit (1)
- # shadow-cljs (123)
- # specter (7)
- # sql (5)
- # test-check (4)
- # tools-deps (38)
- # vim (20)
- # yada (9)
thanks @hiredman. As soon as I add the line :jvm-opts ["--add-modules" "java.xml.bind"]
to project.clj, I can run lein run -m myapp.core
but nothing happens š
http-kit 2.3.0 was released with the fix for JDK 9. You can remove the jvm-opts and upgrade http-kit
(defproject myapp "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url ""
:license {:name "Eclipse Public License"
:url ""}
:jvm-opts ["--add-modules" "java.xml.bind"]
:dependencies [[org.clojure/clojure "1.8.0"]
[compojure "1.6.1"]
[http-kit "2.2.0"]])
I just see a blinking cursor
in myapp.core I have
(ns myapp.core
(:require [compojure.core :refer :all]
[org.httpkit.server :refer [run-server]])) ; httpkit is a server
(defroutes myapp
(GET "/" [] "Hello World"))
(defn -main []
(run-server myapp {:port 5000}))
shoot, I just realized itās actually runing on http://localhost:5000/
I was expecting to see somthing in the console !!!
well thank you @hiredman !!!
Just wanted to recommend Russ Olsen's Getting Clojure for anyone looking to learn the language. Coming from Ruby I was excited to find Russ had written something so comprehensive for Clojure, and it's the most accessible of the books I have access to. I'm working through Joy of Clojure, referring to Getting Clojure when I get stuck or want more background....it's a nice combo!
Yes, I can even recommend it as a refresher if you've been playing with Clojure for some time. There are some interesting bits that you don't find in other books - I wrote a short review here: https://www.goodreads.com/review/show/2336863949
Iām current reading https://www.braveclojure.com/, do you think Getting Clojure is a good choice after I finish it? @U06BE1L6T
I think it's a good choice in general but I guess I tend to read lot more than people normally do. If you've already started Brave Clojure and like it, it may be better to stick with it and experiment a lot - exercises, pet projects etc.after you gain some real experience you may want to read Clojure applied or other more advanced book
It might be best to glance through it quickly (inspectional reading) and decide on your own. You can even use it as a supplementary material if something is not clear in Brave Clojure.
Back then I started with Living Clojure which was nice too - it mentions some web related libraries, community resources, etc. too
If you are interested you can check out the post I wrote back then: https://curiousprogrammer.net/2017/02/15/my-clojure-learning-strategy/
Thanks @U06BE1L6T, Iāll check this out!
What is the current consensus on using <project>.core as your main library file? Is that still the encouraged scheme?
I think thatās the most common convention.
not encouraged or discouraged - do whatever you want
We're making a lot of use of functional core/imperative shell, so a lot of our main lib files are <library>.shell š Or we end up in a situation where you import <library>.core in your <project>.core (for composable builder functions etc) and <library>.shell in your <project>.shell (for the functions that actually execute the built requests)
iām curious, whats does cursor mean in this context?
mathematically there would be a poset structure between the atoms, with the minimum being (atom nil) and the maximum be (atom whatever-the-whole-state-is)
not quite. Atoms can have invariants. You can used refs to coordinate change across multiple pieces of state, but usually ppl usually stick the simpler model by pushing all there state into an atom.
You can use something like Datascript to make it easier to deal with the data.
If the issue is querying semantics.
I believe Om Next (now fulcro) had cursors, i never fully grokked the idea. Maybe ask there?
say I have a namespace that relies on just one piece of the state. I don't want that namespace know anything about the state other than the part that concerns it
#fulcro
@UA2JG2Y11 i understand what you just said about state, but i havenāt understood what you mean by āknow aboutā. If you keep the state in a atom, and two things have an invariant about how they need to update together, then it seems to solve this problem of āisolationā which i feel is more about ācorrect coordinationā. But i dont have a background in this type of thing, so you might have some concerns or ideas i dont understand š
@U61HA86AG seems to me that those libs are smuggling oop into clojure, which is what I am trying to avoid
let's say the whole state atom x is a database like datomic, and I want to shard that database such that different namespaces can have access to parts of it through names x1 x2 x3
@U0DJ4T5U1 I mean, a function that only cares about the :foo key in the state, be passed an atom called foo that is in sync with the state
Can you define what you mean by ācare aboutā?
typically ppl have to solve the problems that sharding their DB (Separating it in space) causes.
because now you have to manage state across time and come up with a coordination protocol that factors in time.
Iām trying to understand what you stand to lose by putting the state in one atom and just having different query functions that access different parts. The results of which, could be feed to functions that are co-located in namespaces how ever you want. Iām genuinely interested in what your talking about, i have thought about this a bit myself.
f cares about x (where x is a part of an atom called s) = f only reads and modifies the x part of the state
I feel like were talking past each other. Here is a simple of example of what i mean:
I store my state in a atom:
(def foo (atom {x: 1, y: 2}))
two functions:
(defn update-x (swap! foo update [:x] inc))
(defn update-y (swap! foo update [:y] inc))
These functions can be put in your separate namespaces. They only know about x and y. This seems to fulfill your needs.
Would putting x in it's own atom do that?
@UA2JG2Y11 reagent reaction
might be useful
You can use make-reaction
like (reagent.ratom/make-reaction #(get-in @parent-atom [:path :path]))
I don't know if I understood correctly, but what came in to my mind was using add-watch to track chances to the source atom. https://clojuredocs.org/clojure.core/add-watch
Unless it is a computational intensive task, and you want to prevent recalculation you could always derive from source atom
Do you have some rule-of-thumb regarding namespaces/-qualified keywords/functions?
I donāt use ns-qualified keywords and while Iām designing my namespaces - I just put everything together waiting to something to emerge, and it seems fine.
And Iām thinking to introducing namespace-qualified keywords to my project, and I have fears that Iām going to get a lot of recursive namespaces, so Iād have to namespace my keys fully :project.name.lib/keyword
instead of (:require '[project.name.lib :as lib]) ::lib/keyword
So, to paraphrase, the question is āwhen does keyword belong to this namespaceā
the namespaces used for keywords and the namespaces used to organize code are not the same
data will live for a long time, often in external stores (databases), code changes so often and so much that version control exists, so tying names in data to names in code isn't a great idea
aliased keywords ('::') tie names in your data to names in code, and also make your code brittle (moving a function to another namespace suddenly changes the data it returns)
namespace keywords vs real namespaces confused me at first too, the book I was reading didn't make a clear distinction I think
I donāt think that is at all what he said :)
Iām having feeling, that it shouldnāt be a problem: everytime thereās a recursion, you just extract those keywords to separate namespace.
@lockdown- I am against using the same namespace names for code (often changing) and data (accumulating)
the distinction is maybe more of a thing in larger projects. I would prefer something like :projectname/user
to :some.namespace.in.project/user
, and maybe even :orgname/user
@troglotit You can use (alias 'lib (create-ns 'project.name.lib))
without needing an actual code namespace for your ::lib/keyword
@lockdown- An adjunct to that is that I tend to have data specs in their own namespace with almost no code (perhaps just some predicates that those specs use) so, again, qualified keywords that don't match code namespaces (although they match the spec namespace).
Hi guys, I have issues with using cljss package. Sorry, maybe it's so stupid, but I'm not able to import macros (:require [cljss.core :refer [defstyles]])
. I always get error Invalid :refer, var cljss.core/defstyles does not exist
. It's official usage recomendation from package github page https://github.com/roman01la/cljss. Any ideas?
@UAWQ6PNGN In ClojureScript, I believe you have to use :require-macros
-- see https://clojurescript.org/guides/ns-forms
Hi. How would one go about printing out a result of all the :tokens in a tree or nested structure?
one option
user=> (into []
(comp (filter #(and (coll? %)
(= (count %) 2)
(= (first %) :token)))
(map second))
(tree-seq coll? seq
{:token "a" :b {:token {:token "c"}}}))
["a" {:token "c"} "c"]
I may have misunderstood your definition of "token" here
So i'm struggling with designing my application in clojure. It's less a problem with clojure but moreso thinking functionally. I mostly write boring business apps and i'm used to OOP. Anyways, using records and functions to encapsulate a domain in my app has been a mental challenge to switch to and i'm wondering if anyone can point me to some non trivial yet still simpleish repos/examples of clean well designed clojure programs
@dfcarpenter apps that i really admire, there are many of them out and about! I don't know what you're wanting to make, here is a really nice application for online chat that uses a server and a clientside db. incremental commits on the server are broadcast out to all peers -- it's really very efficient and fast, and i think the code is nice for reading. i'm always looking for good source to read so i'm curious what others will say http://tonsky.me/blog/datascript-chat/
@sova Thanks, ill check it out.
Also are there any best practices around when to use defrecord, defprotocol and deftype. It seems many people do without them but they can serve a purpose. Is seems its more than a preference and each confer some utility but knowing when seems tricky
Hmm, they all sound good for clarity sake when appropriate. I don't know of any good use-cases for those, myself. However, there is more info on the selection here: https://clojure.org/reference/datatypes
@dfcarpenter a good rule of thumb is to use hash-maps and functions whenever possible, when you need runtime extension a defmulti is better than a regular function, if you have multiple methods that go together, you can dispatch on type, and you need runtime extension, then protocols make sense.
you'll usually want a record with a protocol, sometimes a reify or deftype
@noisesmith Ahh ok that was helpful. Thanks
it's very easy to turn code that's function on map into protocol / defrecord code
(the opposite is less likely true)
so use functions and maps until you need features these other things provide
Thank you!
@dfcarpenter I found that when I wrote oop code, I rarely actually used polymorphic features (and when I did, it would have been better to compose rather than inherit). I mostly used them for organization and naming. you can accomplish that by putting your āmethodsā in a namespace and passing around a map that would previously have been the āproperties/fieldsā of your object. Suddenly youāll find that many methods only need a tiny portion of the object state, and you can make them simpler by passing only what they need. My point here is that if you donāt need polymorphic dispatch, you donāt need that many language features.
that's true, it's a good explanation of what I meant by "just use maps and functions"
Hi, I want to "conj-in" at atom I have... I'd like to associate multiple numbers ... sets.. #{12 24 48 etc} with keywords in a part of my atom. how can i do append-only operations into the set
if I understand you correctly, the pattern often looks like this:
(ins)user=> (def a (atom {}))
#'user/a
(ins)user=> (swap! a update-in [:a :b] (fnil conj #{}) :x :y :z)
{:a {:b #{:y :z :x}}}
(cmd)user=> (swap! a update-in [:a :b] (fnil conj #{}) :l :m :n)
{:a {:b #{:y :n :m :l :z :x}}}
lovely, now say the keyword :b
is actually determined by a list of strings... how can I run this swap line for each string in a list?
you could do it inside a doseq
on the list
or make a single function that does all of the update-ins to reduce contention on the atom if that's a concern
hmm. it's not a huge concern, but sounds like it would be faster
#(-> % (update-in ....) (update-in ....) ...)
- common pattern in reagent where each swap is a re-render of something
I guess if it's a list of keys at runtime, you want reduce
instead of ->
I'm not sure how to use doseq on a vector of strings.
same way you doseq on anything?
user=> (def strs (atom []))
#'user/strs
user=> (doseq [s ["hello" "world"]] (swap! strs conj s))
nil
user=> (deref strs)
["hello" "world"]
same idea, yeah
(ins)user=> (doseq [s ["a" "b" "c"]] (swap! a update-in ["strings" s] (fnil conj #{}) "hello"))
nil
(ins)user=> @a
{:a {:b #{:y :n :m :l :z :x}}, "strings" {"a" #{"hello"}, "b" #{"hello"}, "c" #{"hello"}}}
Oh hey, beautiful
Thank you very much
can also do this @sova
user=> (run! (partial swap! strs conj) ["hello" "again"])
nil
user=> (deref strs)
["hello" "world" "hello" "again"]
oh cool, i have been trying to wrap my mind around partials lately.
I have a function that looks like this:
(defn props
[val-1 val-2 val-n-1 val-n-2]
{:prop-1 val-1
:prop-2 val-2
:prop-3 {:nested-prop-1 val-n-1
:nested-prop-2 val-n-2})
It was created because I was originally writing the map everywhere and it just felt like a lot of duplication. So I moved it into a function. Now I am running into a situation where I have the same function above, but I duplicated it everytime I needed to add another property (just coding quick) because I need the same basic map structure with the addition of one other property here and there.
Two questions:
1. What would be an idiomatic way of reducing a lot of this duplication? One solution is something like (defn [] (assoc (props val-1 ...) :new-prop val-3 ))
but Im not sure that is the best way
2. Given that the function has 4 params, might it be better written using keys?if you provided a map, it wouldn't be far from this idiom for expanding flattened paths
(cmd)user=> ((fn [m & kvs] (reduce (fn [m [ks v]] (assoc-in m ks v)) m kvs)) {:a 0} [[:b :c] 1] [[:d :e :f] 2])
{:a 0, :b {:c 1}, :d {:e {:f 2}}}
Sorry, you mean if I update my props
function to accept a map and vectors like (as you illustrated above) {:a 0} [[:b :c] 1] [[:d :e :f] 2]
This is where functional programming blows my mind. I like this solution, but why does it feel like it requires a little more thinking for a consumer (another dev) to figure out what they are allowed to pass? What I am thinking is the consumer would have to know the exact structure that they need to pass into what has become, a very generalized function.
For example, everywhere this is called, when passed to a particular function, the caller would have to use, for example, {:a 0} [[:b :c] 1]
what I mean is that if it takes a map for the args, you can substitute keys to paths and use the above idiom
(and that substitution can be performed with a simple hash-map)
hmmm, I think I am missing it š
never mind, it probably doesn't apply here
it's a way to transform a flat sequence of paths and targets into a nested structure
hmmm was the suggestion to update what I had to something like this:
(defn props
[{:keys [...]}]
(fn [m & kvs] (reduce (fn [m [ks v]] (assoc-in m ks v)) m kvs)))
So I remove my hardcoded map and pass in a map as the arg like (props :val-1 0 :val-2 "hi")