This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-05-15
Channels
- # announcements (2)
- # babashka (137)
- # beginners (96)
- # calva (3)
- # cider (11)
- # clj-kondo (8)
- # cljs-dev (161)
- # cljsrn (21)
- # clojure (78)
- # clojure-europe (47)
- # clojure-france (1)
- # clojure-losangeles (1)
- # clojure-nl (4)
- # clojure-spec (24)
- # clojure-uk (9)
- # clojuredesign-podcast (4)
- # clojurescript (39)
- # conjure (2)
- # core-async (27)
- # cursive (36)
- # datomic (54)
- # emacs (6)
- # figwheel (9)
- # figwheel-main (46)
- # fulcro (25)
- # graalvm (8)
- # helix (30)
- # hoplon (6)
- # hugsql (3)
- # jobs (5)
- # leiningen (7)
- # luminus (12)
- # nrepl (20)
- # off-topic (20)
- # pedestal (16)
- # re-frame (14)
- # reagent (3)
- # reitit (3)
- # remote-jobs (5)
- # rum (25)
- # shadow-cljs (60)
- # spacemacs (10)
- # vim (2)
- # xtdb (36)
How can I write the following macro?:
(db-event :add-to-cart [product-id] {:cart {product-id (-> db :cart (get product-id) inc)}})
should give
(db-event :add-to-cart [product-id]
(assoc-in db [:cart product-id] (-> db :cart (get product-id) inc)))
and
(db-event :foo [resp] {:abc {:def resp :efg (more-stuff resp)} :foo1 {:bar1 (stuff resp)}})
should give
(db-event :foo [resp]
(->
(assoc-in db [:abc :def] resp)
(assoc-in [:abc :efg] (more-stuff resp))
(assoc-in [:foo1 :bar1] (stuff resp))))
so basically doing a bunch of assoc-in, just giving a map of all the things that are to be changed.
if it helps, I'm trying to extend the db-event macro which is this:
(defmacro db-event [event-key params & body]
`(do
(re-frame.core/reg-event-db ~event-key
(fn [~'db [_# ~@params]]
~@body))
(defn ~(symbol event-key) ~params (re-frame.core/dispatch [~event-key ~@params]))))
:thinking_face: “def a fn that dispatches by event to an anonymous fn which is registered by that event.”
The best way to write a macro is to write a function that does what you want, then write a macro that expands into a call to that function
I likewise will often write my macros that way -- and I think it does speak to the nature of the macro a bit; to me, its easier to think of the body of a macro as not the macro itself, but an inline defined function that the macro will smuggle into the compiler.
what would a function say assoc-map look like, that takes in a map1 and another map2 and assocs in map1 into map2, basically embeds map1 into map2?
(defn deep-merge "Recursively merges maps." [& maps] (letfn [(m [& xs] (if (some #(and (map? %) (not (record? %))) xs) (apply merge-with m xs) (last xs)))] (reduce m maps)))
I likewise will often write my macros that way -- and I think it does speak to the nature of the macro a bit; to me, its easier to think of the body of a macro as not the macro itself, but an inline defined function that the macro will smuggle into the compiler.
What’s the best way to iterate over a highly varieties custom nested map and vector data structure and collect all the values that have a specific key across the entire structure?
@bardiapourvakil cljs.user=> (map :a [{:a 1} {:a 2}]) (1 2)
@bardiapourvakil I can imagine a lot of different scenarios with that description, it'd be easier to answer with some examples
What is the best way to check if a word consists of only letter and/or one colon?
I've written the following: (some #(= arg %) (vector (re-matches #"[a-zA-Z]+:[a-zA-Z]+" arg) (re-matches #"[a-zA-Z]+" arg)))
#"[a-zA-Z]+(:[a-zA-Z]*)?"
Thanks!!
There are some pre-defined character classes in Java RegEx. E.g. \p{IsAlphabetic}
can match any Unicode alphabetic characters. They are sometimes useful.
https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html
It wasn't easy but I really like the result(performance/maintainability). Hopefully future releases/apps wouldn't be as difficult
What did the more difficult part for you ?
The most difficult part was absense of someone with practical experience in clj/cljs ecosystem so I had to explore all those(fantastic) choices myself. So my onboarding to CLJ world was rather tough - started with Luminous(clj/cljs), then got excited about Fulcro(still got stuck after a few weeks of learning it), switched to macchiato(got it working locally but couldn't make it into production - slack channel and macchiato's small community is rather very small so I can't complain). Eventually I rewrote it using Luminus stack hoping Heroku's 512Mb RAM limit would be enough). I'm currently monitoring this app - RAM usage is steady at 60%(318Mb), performance it really good
Clojure community is super friendly and super helpful but when you have deadlines.. you can't just spam it with dozens of questions every hour 🙂
same problems here too, sometimes I was waking up 2 AM and 3 AM just so I can ask questions on the slack since in my timezone either people were sleeping or working, so not able to answer.
It's a bit easier if one can setup a CI pipeline, but the whole cloud direction is like getting in brace with Bezos, I am not sure how that's going to work out. OTOH, the language itself would benefit from more diversity anyway, so each possibility has it's ups too.
The time zone issue is real. If you post something at morning time(in Europe), there is high chance no one gets to it by the time America wakes up 😄
which is late afternoon, early evening. If you want to have a conversation that goes back and forth a few time, it's quite expected to take until 22:00 there is some exhaustive resolve
Thank for the details @U0113AVHL2W 👍
In a line like
user=> #com.stuartsierra.dependency.MapDependencyGraph {}
; #com.stuartsierra.dependency.MapDependencyGraph{:dependencies nil, :dependents nil}
what is the #com...
which interprets the map as a dependency graph called?https://clojure.org/reference/reader#tagged_literals it is tagged literal
Thanks! Do those that turn regular data structures into more specific kinds have a special name? Because there are other kinds of uses for #something, right?
Actually in this case I think that’s a Java constructor, not a tagged literal
It happens to be a Java constructor for a Clojure record in this case
Are there any docs for all possible uses/meanings of #?
https://clojure.org/guides/weird_characters is probably the closest
In general the # is the character that triggers the dispatch reader
You can actually find the definition of the dispatch table here https://github.com/clojure/clojure/blob/30a36cbe0ef936e57ddba238b7fa6d58ee1cbdce/src/jvm/clojure/lang/LispReader.java#L109
So that says what to do based on the character after the #
That is so cool! I will have to learn to read the java source eventually 🙂
suppose I have a macro that has a body parameter, and I want to apply a function only to the last statement in the body if there are multiple ones:
(defmacro foo [foo bar & body]
~@body
)
so basically I want to split the body into all-but-the-last and last. How can I do that?last
and butlast
?
Is it possible to have a function that takes an optional keyword argument, but the keyword itself is optional? That is, I want (f 2)
to work too:
(defn f [& {:keys [a] :or {a 1}}] a)
; (f) => 1, (f :a 2) => 2
; (f 2) => Execution error (IllegalArgumentException) No value supplied for key: 2
I am used to def f(a=1): return a
in Python. Works with f()
, f(2)
, and f(a=2)
.
you could add another arity ([a] ...) to do that
I wouldn't recommend it, but it is possible :)
(defn f
([] ...)
([a] ...)
([& {:keys [a] ...}))
I think it will complain about mixing fixed arity with variadic one
ah right, you might need to get rid of the no arg there
(defn foo
([] (foo {:a 1}))
([{:keys [a] :or {a 1} :as m}]
(if (map? m)
a ;; here should be actual function code
(foo :a m)))
([a & args]
(foo (apply hash-map (list* a args)))))
(foo) ;; => 1
(foo 2) ;; => 2
(foo :a 3) ;; => 3
I end up with this. Arity 1 is the mainbut I would not recommend to use it) probably not the best way to structure function api
the arities can invoke each other
Yeah, I actually like the strictness of having to supply the kw; makes it impossible to make a mistake in the ordering of arguments.
You could always take a map as an argument
Hello 👋
Is it possible to use defprotocol
with :pre/:post ?
defprotocol
doesn't provide function implementations -- it's more like a Java interface -- but :pre
/`:post` are part of an implementation so, no.
I thought so
You also cannot Spec a protocol function by the way: which is why it's fairly common to have wrapper functions that call the protocol functions (so you can Spec the wrapper or have variadic functions etc).
^ that strategy, a wrapper that calls the protocol function will also work for :pre/:post the same as it does for spec
in general, in stuff we build in things like spec, we almost always have a wrapper function around protocols rather than using them directly
it's a very useful hook point for a variety of reasons
Hi all 👋, I would like to get some more insights about the philosophy behind "simple". I kinda get what is meant by that, but I would like to get some practical adivice how I (as a less experienced programmer) can judge that a solution is "simple" and how i can build a "simple" solution. Any resource, regarding this topic, to study will be much appreciated.
for a large part it's recognizing how Clojure's design decisions are meant to be simple, and making things that are compatible with those choices
you’ve probably already seen https://www.infoq.com/presentations/Simple-Made-Easy/ , but just in case
I think the biggest items: use immutable things, program in terms of values, use abstract structures not domain specific ones, prefer 100 functions on 1 data type over 10 functions each on 10 data types
but that's just my elevator pitch version
when thinking about simplicity, a decent place to start is trying to break down your design down into who, what, where, when, why, and how. it’s a very concrete place to start which should hopefully get the wheels turning.
hey thanks for the answer I m familiar with the suggestion, i guess my question aims more for the bigger picture. Like when i desing a system. How to judge if it is still simple after writing a lot of code
ideally, you want to produce a “simple” design before you write a lot of code
if you haven’t, chances are good that your design isn’t simple
i’m not really a TDD (test driven design) person, but TDD will highlight where your design isn’t simple. basically, if your design is simple, then you can take your program apart. if you can take your program apart, then it’s typically much easier to test
some questions you can ask to see if your design is simple: • is your program built from smaller pieces? • what are the smaller pieces? • can the pieces be used in different contexts? • can you run a piece of your program in isolation? (ie. can you run a part of your program without setting up a context that requires the rest of your program)
Focus on data and values instead of complicated abstractions and wrappers. When you have data you can apply powerful Clojure functions to it. Simple is good. It means you can use tools you are familiar with and not have to guess how you are supposed to deal with something. All the problems start to look familiar and tractable. (as opposed to, for example, having to learn a new API every time you interact with a different object/class)
@U013CA8A28J ty for ur input, clojure makes this approach especially easy. Where I struggle is when I try to apply these ideas in other languages for example java. Do u have any resources or examples outside the clojure ecosystem where the principles of "simple" are applied?
@UP2FUP0TT Are you asking how you can make Java as simple as Clojure? Oh, that made me laugh 😆. You cannot. It is designed around the class system. Java code can only take the ideas so far because the language doesn't help you. You can do certain things, like rely on factory methods instead of instantiation with new. That simplifies things for you, but much of this way of programming depends on the language itself.
Take JavaScript as an example. There, your functions are first class and you have data literals just like Clojure. That makes it a lot easier. Many of the "patterns" of Java just fall away and you use functions/literals instead.
There is a really great talk by Douglas Crockford where he brings up something called "parasitical inheritance". It's like a decorator pattern. Say you have a function makeDwelling which produces some kind of specification map for houses, like number of rooms, area, furnishings, etc. You could then create a new function that specializes on top of that, such as makeLakehouse:
function makeLakehouse() {
const house = makeDwelling();
return {...house, hasLake: true };
}
Nice and simple. No need for classes or any rigid hierarchy. You basically have a factory function and then use it as part of another factory function. It sounds almost ludicrous to call it a factory function because it's so simple. You get nice encapsulation and the ability to change the implementation later. In Java, this is simply not an option. No matter how you decide to implement it, you must use classes and methods, and you'll probably have getters and setters. There will be boilerplate. It's just the way it is. JavaScript has its own problems, but you can at least choose to simplify your life and use the nice parts of it.
So I'm having an issue with the reagent template project. I ran 'lein new reagent myproject' as described here: https://github.com/reagent-project/reagent. But when I make changes to source, I have to manually hit reload in the browser to get updates. I tried to implement the fixes here: https://stackoverflow.com/questions/46287101/figwheel-doesnt-detect-most-changes-in-my-code#46298820 to no avail. How do I get figwheel to reload the browser?
Is there a good recommendation for finding a "tutor" or someone to help me with my learning? I don't mind paying. I've found good resources for learning the language generally but hitting some basic issues in my tooling and looking to walk through with someone
If you don't mind paying, I would recommend contacting Eric Normand at https://purelyfunctional.tv and find out what he might charge, or if he has recommendations for tutors.
Clojure tooling tends to be somewhat disparate, with at least 5 major different IDEs/editors each with their own Clojure-specific add-ons, Clojure vs. ClojureScript, etc.
There are specific channels on this Slack for all of them that I know about, e.g. #cider #emacs #calva #cursive #vscode #clojurescript #shadow-cljs #figwheel etc.
Thanks @U0CMVHBL2 I'll try Eric! Not sure if its an IDE problem or user problem (me) but I've been having a hard time getting programs from tutorials to run on my machine, looking to break through that barrier so I can learn by emulating
@U0135E0PFDX, you may find https://exercism.io/my/tracks/clojure and #exercism useful
I can highly recommend Eric's videos and he is available for you 24/7 via e-mail, very excellent service he provides! Take your Clojure to the next level with some of his excellent videos.