This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-09-21
Channels
- # admin-announcements (1)
- # announcements (6)
- # babashka (8)
- # beginners (134)
- # calva (18)
- # chlorine-clover (1)
- # cider (6)
- # circleci (6)
- # clj-commons (111)
- # cljsrn (13)
- # clojure (95)
- # clojure-australia (2)
- # clojure-europe (15)
- # clojure-nl (1)
- # clojure-spec (52)
- # clojure-uk (17)
- # clojurescript (4)
- # datavis (9)
- # datomic (8)
- # docker (2)
- # emacs (15)
- # events (7)
- # fulcro (6)
- # graphql (1)
- # gratitude (1)
- # introduce-yourself (2)
- # kaocha (8)
- # meander (87)
- # minecraft (2)
- # music (2)
- # off-topic (20)
- # portal (119)
- # releases (1)
- # reveal (55)
- # shadow-cljs (34)
- # sql (36)
- # tools-deps (9)
- # vim (8)
- # xtdb (39)
Hello I can do a macro like this ...
(defmacro test1 []
(let [h 1]
h))
but how do I get it to work if I want to use a syntax quote?
(let ...)`I want to get this to work actually ... but not sure where to put the ~
(defmacro test1 []
`(let [h 1]
h))
which is somewhat needed for macros since otherwise you could interfere with local variables
Hello if I have a macro that takes in a vector of symbol and key, how do I get the symbol and remap the value of it.
I can get "a" but as a string with
(defmacro test1 [v]
`(let [~@v]
~(str (first v))))
(test1 [a :az
b :bz])
hmmm perhaps I can put them as keywords first ...
(defmacro test1 [v]
`(let [~@v]
~(mapv keyword (mapv first (partition 2 v)))))
(test1 [a? :az
b :bz])
Okay, I have reached a point in my macro where I get
((:tested? true :name "A")
(:tested? false :name "A")
(:tested? false :name "B")
(:tested? false :name "C"))
and what I want to do is to within a let binding, remap tested?
and name
to the corresponding valuesHow do I get something like ...
(defmacro test1 [a body]
`(let [a []]
~@body))
(test1 z (count z)) => 0
to work?usually you'd want (defmacro test1 [a & body] ...
- the body is a seq of exprs and then you unquote splice them into the result
for example see (source when-let)
Yeap! I have it as [a & body]
but was trying to get a minimal example so i left out the &
now i have another issue though and I'm not sure how to proceed ... I want to do something like ...
(defmacro test1 [a & body]
`(let [(interleave (map symbol symbols#) group-type#)]
~@body))
in this and most of the steps above I have no idea what you're trying to do. in general macro stuff is easier to answer if you can state a) what a caller of the macro should write and b) what the macro output will be. doing this here helps others help you but also you'll find it often may help you see the answer yourself
where (interleave (map symbol symbols#) group-type#)
is
((tested? true name "A")
(tested? false name "A")
(tested? false name "B")
(tested? false name "C"))
and another helpful tip is to use macroexpand-1
if you haven't found it yet - you give it a quoted form and it will expand the macro
(defmacro test1 [a & body] `(let [~a []] ~@body))
(macroexpand-1 '(test1 abc false true))
;;=> (clojure.core/let [abc []] false true)
Alright! I guess I was having trouble explaining my problem because I'm new to macros and also because it is a coding task (writing of the macro) I received for a role, so am trying to do it myself while seeking help for portions of the problem
a macro is just a function from input code to output code. if you can write down exactly what the input and output are, the macro is easy
hmmm let me try proceeding that way then 🙂 , felt some difficult also because I feel that macro is pretty complicated but let me give it another shot ...
don't worry about the macro, just start from the user writes ... the code that is run is ...
I think we're past rule 1 :)
Yeah, but it's always worth a reminder...
Actually now that I look at it ... I'm really only left with this one step ... which I guess could be described as how do I do something like apply
for a let
I want to do
`(let [(interleave (map symbol symbols#) group-type#)
~group-data group#]
~@body)
but I need to remove the ()
since (interleave (map symbol symbols#) group-type#)
gives (treated? true disease-name "A")
instead of treated? true disease-name "A"
and I can't use ~@
as I will get Unable to resolve symbol: symbols# in this context
(let (vec (interleave (map symbol symbols#) group-type#)))
would work too but it doesn't seem to work that way ><
Or is this an impossible task? Cause I can do
`(let [x# (interleave (map symbol symbols#) group-type#
~group-data group#]
x#)
but not
`(let [x# (interleave (map symbol symbols#) group-type#
(first x#) (second x#)
~group-data group#]
x#)
@zackteo You might do better writing this as a function that takes a symbolic expression and returns a symbolic expression.
That will let you get the logic of the macro right without worrying about quotes and splices and so on.
I tried doing this but ended up encountering more weird problems like https://stackoverflow.com/questions/26684810/clojure-macro-dont-know-how-to-create-iseq-from-clojure-lang-symbol
Okay I got it working to the same point and eliminated a bunch of quotes and splices etc but am left at the same issue of the let binding
Okay ... i made progress ... but is there a way to do the following but in a loop depending on items in bindings/group-tyoe#?
(let [~group-data group#
~(first bindings) (first group-type#)
~(first (rest (rest bindings))) (second group-type#)]
~@body)
I'll just repeat my earlier advice: write a function that takes a quoted symbolic form and debug it that way.
Okay! I think I have an idea after taking a shower as well. But thanks @U04V70XH6! I think the way I was working with symbols before caused a lot of additional difficulties which made me give up on starting with a function
Oh. I also realise that I had misread your earlier advice as remove the ` where possible to eliminate confusion with slices etc
@U04V70XH6 with all due respect, I seem to realise again that the problem being defined as taking in
[treated? :treated
disease-name :diagnosis]
rather than
['treated? :treated
'disease-name :diagnosis]
creates a bunch of problems and strange behaviour since treated?
and disease-name
can't be evaluatedEnded up realising that the use of recursion seems to be the most idiomatic and natural way. So went with that o:
Writing a macro as a job application coding task? Damn.
In Common Lisp I never went a day without writing a macro, but with Lisp-1 my only macros are in my dataflow library Matrix, where there is lots of boilerplate to hide, and an anaphoric self
are vital to the DX.
Okay I think I can make a recursive macro but is there a way to do so without recursion ?
I was write the practice code in vscode + calva. why show syntax error when I press CTRL+Enter for run code
What is the rest of that error message? Can you copy'n'paste the text instead of a screenshot?
Syntax error compiling at (d:\E\clojure\clojure_code\src\vector\example.clj:5:1). ; Unable to resolve symbol: println in this context
Maybe you haven’t loaded the file? ctrl+alt+c enter
. Calva’s REPL needs a first loading of something before it finds even core functions.
Hello all, I have a defmulti that I use as validation an array like
(defmulti processar-no (fn [{:keys [tipo criar]} _] [tipo criar]))
(defmethod processar-no ["Projeto" "NÃO"] [{:keys [valor idProjeto]} ac]
...)
(defmethod processar-no ["Projeto" "SIM"] [{:keys [valor idProjeto]} ac]
...)
How do I configure a method for default stuff?So I am trying to build out my first big project, a full stack web app and was hoping for some general guidance.
I am using Reagent/Re-Frame on the frontend and ring/reitit/jetty on the backend and currently have the backend and frontend connected correctly but it's basically just the front end creating the needed js and my backend slurping in the index.html
. I'm a little confused though on how to actually start sharing more dynamic data between the two.
I was thinking of having the frontend basically just handling the UI but when the user submits a form or login or whatever, I want that data to be sent to the backend where it will process it, query any needed api's and/or db for data, and then send that response back to the front end to display. Am I thinking about all this correctly?
I'm wondering if I should just be using the front-end for all of this (since it's supposed to be a SPA anyways, right) and then what do I even need a backend for? Should I just be using a "backend as a service" like firebase instead?
I like my original idea of having the backend doing all the heavy lifting besides UI but then should I be using reagent/re-frame vs just doing it all with server side rendering with html templates? How exactly do I send a form submitted data to my backend and then vice versa? What should I be searching for there.
Sorry if this is too general but I'm not sure where to ask basic web dev questions with a clj/cljs slant.
here is the current repo so far if it helps to see if I'm setting this up correctly: https://github.com/Chase-Lambert/ai
I'm trying to figure out how I'm going to send the data posted in the frontend/ai/core.cljs
query form to my backend/ai/query.clj
api business logic.
I learn from this book https://pragprog.com/titles/dswdcloj3/web-development-with-clojure-third-edition/. There's source code available for download. On the client side you can use cljs-ajax lib to send your client side of data(encapsulated in a map) to backend by json/edn format. On the backend use metosin/reitit libs to parse the client http request and you got yourself back a map for backend processing. The same libs takes care of sending the result to client, again as a map. Another good resource for what libs to use is this https://luminusweb.com/docs/guestbook.
Ok, yep, I got that book. Time to dig in more. I'll check out that library too. Thanks!
{:a 1 :b 2}
-> {:x/a 1 :x/b 2}
Is there some to way to namespace all the keys in a map like this without iterating over all the keys using something like reduce or map?
if a literal, you can use this shorthand #:x {:a 1 :b 2}
. If it is a value there is no way to do it without iterating over all of the keys
It’s done with a reader macro, so using the #:x
prefix can’t be done with a macro.
The only other way would be to use update-keys
in the new 1.11.0-alpha2 (https://github.com/clojure/clojure/blob/b8132f92f3c3862aa6cdd8a72e4e74802a63f673/src/clj/clojure/core.clj#L7952)
(update-keys {:a 1 :b 2} #(keyword "x" (name %)))
@dpsutton what do you mean when you say a value? You mean manipulating it through a symbol?
(let [x {:a 1 :c 2}] x)
x
is a value in this expression. contrast that with the literal {:a 1 :c 2}
you could also make a wrapper type that intercepted the calls to lookup and handled the namespace stuff but that's super not recommended unless you have profiling reasons to do so
That's a little beyond my needs at the moment, but I am curious... what would you use to implement the wrapper type? I haven't started doing stuff like that yet.
to make a new type you usually want deftype
Ah, this is covered in that chapter in Brave that I keep deferring for some reason 🙂 almost there.
also, new data types are needed very rarely in clojure, in comparison to most other languages
then you'd implement all the protocols a clojure hash-map implements with apropriate methods for the behavior you need
potemkin
has def-map-type which is meant for this use case (as a warning, it's explicitly a library of "ideas that are almost good", and wanting to do something potemkin offers is probably a sign you want to step back and redesign...) https://github.com/clj-commons/potemkin
hello everyone. is there a way do something similar to agents but with a ring-buffer as a queue of actions?
i don't want to start the next action until the previous is finished, but I'm also only interested in the latest action
so if multiple actions are sent to the agent while it
it's doing something, I can discard all but the last one
@joao.galrito the closest match to that behavior I know of is using a core.async channel with a dropping buffer
there's probably a less complex / better performing way to do it with a java queue if you don't need core.async's other features
@joao.galrito if you just want ignore all but the latest message, you can do something like this
(let [a (agent :thing)]
(send a (fn [x]
(when (-> *agent* .getQueueCount (= 1))
(prn 'do-latest-thing)))))
which will skip messages when there are more than one in the queue.thank you @noisesmith and @l0st3d 🙂
Wondering what the more idiomatic way would be to write the following?
(loop [[{size :size :as x} & rest] [{:size 1 :foo "1"}
{:size 2 :foo "2"}]
res []
low 1]
(if (nil? x)
res
(let [high' (+ low size)]
(recur
rest
(conj res
(assoc x
:low low
:high high'))
high'))))
Basically looping through and adding the low and high range for each of the maps based on their sizemaybe
(let [data [{:size 1 :foo "1"} {:size 2 :foo "2"}]]
(->> data
(reductions (fn [{:keys [high]} {:keys [size] :as x}] (assoc x :low high :high (+ high size))) {:high 1})
(drop 1)))
???i think that's just reducing over the collection. i don't see any control flow the requires an explicit loop unless that's your preferred style
the low
is a state so reduce
can only save you the if (nil?
part when compared to loop
in this case.
also, O(2n) = O(n). If your data isn't huge, traversing twice isn't the end of the world 🙂
the problem above was: calculate absolute bounds for a bunch of entities that you know the size of
(:coll (reduce (fn [{:keys [low coll] :as state} {:keys [size] :as x}]
(-> state
(update :low + size)
(update :coll conj (assoc x :low low :high (+ low size)))))
{:low 1 :coll []}
[{:size 1 :foo "1"}
{:size 2 :foo "2"}]))
and
(map (fn [{:keys [size] :as x} running-total]
(assoc x :low running-total :high (+ size running-total)))
[{:size 1 :foo "1"}
{:size 2 :foo "2"}]
(reductions + 1 (map :size [{:size 1 :foo "1"}
{:size 2 :foo "2"}])))
you can get the highest bound with:
(reduce + 0 (map :size things))
and all the high bounds with
(reductions + 0 (map :size things))
I'm not a fan of the reduce accumulators (or loop-carried states) above having two things in it
So the preferred would probably be the map
and reductions
approach as also shown by @dpsutton?
(let [d [{:size 1 :foo "1"} {:size 2 :foo "2"}]]
(loop [[{size :size :as x} & rest] d
res []
low 1]
(if (nil? x)
res
(let [high' (+ low size)]
(recur rest (conj res (assoc x :low low :high high')) high')))))
Although essentially the same but this looks nicer, right?(let [data [{:size 1 :foo "1"} {:size 2 :foo "2"}]]
(reduce (fn [r {:keys [size] :as x}]
(let [low (:low (peek r) 1)]
(conj r (assoc x :low low :high (+ low size))))) [] data))
you can remove the need to call :coll
on the reduced value by using peek
on the input vector??for a beginner, in the example below, you can find a few subtopics to dive into: • three collection functions (map, partition, reductions) • separating concerns • the fact that clojure.core/map can take multiple collections and apply a function "across" themm • the threading macro ->> • destructuring [lo hi]