Fork me on GitHub
Karen Liu00:04:47

Hello! I’m trying to figure out how to have a collection of vectors where the second element in each vector is the sum of the previous vector’s second element and a constant; like below - but I’m not sure how to approach it. Is it a bad idea to use something like dotimes if I have no side effects?

[10 5]
[10 10]
[10 15]
[10 30]


Yeah, for a lazy sequence... That would be better...

user=> (take 5 (iterate (fn [[x y]] [x (+ 5 y)]) [10 0]))
([10 0] [10 5] [10 10] [10 15] [10 20])

👍 2
Karen Liu00:04:17

That is a lot cleaner than what I trying to do! Thank you!


(deleted my bad suggestions due to misreading the Q!)


I would like to guard against data model changes in a big full-stack project. My feeling is that going full-blown spec and test is going to be a pain to maintain until the data model settles. Currently, I'm thinking of using a combination of hyperfiddle/rcf (which would get turned into proper tests later on) and assertions (`:pre` or truss , to be elided in production). Questions: • Does this sound like a sound approach? • I've seen that assertions can be elided in ClojureScript. Is there a way to easily switch them off in Clojure? (Both for production but also testing.) I'm using deps.edn. Any pointers welcome.


I think assertions can have a lot of value in production - I would use them wisely and keep them always on.


Thanks! I can truss's have! for those that should be kept in production.

Michael Anckaert10:04:55

I got a question about the ->> macro, in the following example, the req is passed as the last parameter to the str function, but I thought that was the goal of the ->> macro?

(defn request-example [req]
     {:status  200
      :headers {"Content-Type" "text/html"}
      :body    (->>
                (pp/pprint req)
                (str "Request Object: " req))})


The last line there will actually become

(str "Request Object: " req foo)
Where foo is the result of (pp/print req) (which I imagine will be nil)

Michael Anckaert10:04:35

Ah, I get it now. Have been mocking some calls around. The use of the ->> macro isn't really required IMO as the result is indeed nil and won't affect the str call. Could this have been a simple do function?

👍 2

If you just want to do both lines, maybe you want do instead ?

:body (do
        (pp/print req)
        (str "Request Object: " req))

Michael Anckaert10:04:51

Yeah, that's also what I'm thinking. Kind of reinforces my belief that there is a lot of bad content on medium :face_with_hand_over_mouth:

🥲 1

I have a DDG addon for Firefox that lets you blocks domains from search results. One of the domains I block is, found its mostly crap.

Rambabu Patina12:04:24

Hello! I have a question with -> macro. How to append key value pair based on if condition. Below is the code snippet I am trying

(def page-data {:title "demo" :type "record" :body "body data" :abc "first" :metadata {:properties {:test-state "test" }}})
(let [new-payload (->
                  (select-keys [:title :type :body :metadata])
                  (assoc :version "v1")
                  (if (contains? (get-in page-data [:metadata :properties]) :editor)
                    (assoc [:metadata :properties :editor] :key "editor" :value "v1" )))]
                    (println new-payload)
But it is returning 'false'. Instead I would like to get response such as
{:title "demo" :type "record" :body :version "v1" "body data" :abc "first" :metadata {:properties {:test-state "test" :editor {:key "editor", :value "v1"} }}}
Your help greatly appreciated!


As @U050ECB92 mentioned, macroexpand is nice for getting an idea of what’s happening. Depending on your preference you might also want to look into using cond-> , though you’ll be adding some truthy indicator to every step that should always be running.

(let [new-payload (cond-> page-data
                    :always (select-keys [:title :type :body :metadata])
                    :always (assoc :version "v1")
                    (contains? (get-in page-data [:metadata :properties]) :editor)
                    (update-in [:metadata :properties :editor]
                               merge {:key "editor"
                                      :value "v1"}))]
  (println new-payload))


I switched to update-in for the example since your snippet was using assoc with a path which will actually turn into a key 😊

(assoc nil [:my :path] :value :another :value)
; => {[:my :path] :value, :another :value}

Rambabu Patina15:04:15

Awesome Thanks @UDB2Q0W13 It works for me.


No probs! Did you try macroexpanding yet? Illustrating what happens by switching out -> with as->:

(as-> page-data x
  (select-keys x [:title :type :body :metadata])
  (assoc x :version "v1")
  (if x
    (contains? (get-in page-data [:metadata :properties]) :editor)
    (assoc [:metadata :properties :editor] :key "editor" :value "v1")))
Since page-data (`x`) is always true, the return value becomes the result from contains? 😊 If you don’t want to insert the value as the first argument you need to create an anonymous function like so:
(-> 1
 (#(if (zero? %) "Zero!" "Not zero")))
or in other words:
(as-> 1 x
 (dec x)
 (#(if (zero? %) "Zero!" "Not zero") x))
The code gets pretty ugly at this point so maybe define a function outside the thread


without giving you the direct answer, one thing I recommend to run macroexpand in your REPL: (macroexpand '(-> a b c)) You'll need to quote the form that you're macroexpanding, but this will give you an intuition for why you're getting an unexpected response (macroexpand '(-> a (if condition then else)))


Doing any IO in a transducer, like an HTTP request to get more data, is a bad idea?


not a bad idea at all


the actual reducing function argument to transduce/`reduce` is often a side-effect. Maybe don't also do IO in the transducer (Remember transducers don't process data, they transform a reducing process that actually does the data processing)

gratitude-thank-you 1

it's not a universal rule


I have a large data set which I need to transform in some ways (map, group-by), and then send an HTTP request to add some more data to it, before saving it in my own DB. The last part I was planning on doing in the reducing function. Is it okay to do the rest inside the xform part of the transducer, or do I need to separate this out in other ways? So the side-effect (writing to DB) is isolated to the reducing function. This sounds like the right way to do that. I'm just not clear if I can make network requests and incorporate the returned data inside the transducer transformation, or if that should be done in the input to the transducer using map or something.

Alex Miller (Clojure team)16:04:06

user=> (hash-set 1 2 3)
#{1 3 2}
user=> (set [1 2 3])
#{1 3 2}

Alex Miller (Clojure team)16:04:18

one takes values, one takes a coll


where do I find "clojure tips of the day"


Always Be Comparing and setting


Use fnil with update-in for missing initial values (0, [], etc)


Use for wrapped in a recursive function to process tree shaped data (fn f [xs] (for [x xs i (f x)] i))

👀 1

ifn? is true for all invokable things (fns, multimethods, keywords, collections, vars, ...) but fn? only returns true for fns. Prefer ifn?

😁 2

You can give otherwise anonymous functions a name to refer to itself by, which is useful for recursion, but the name will also show up in stacktraces so is useful when debugging (fn thisisthename [anarg] anarg)


str is the identity function on strings, and is type hinted to return a String. You can use str instead of adding a String type hint to remove reflection.

👏 1

Use update-in instead of assoc-in, you can always turn update-in into assoc-in using constantly


identity is the identity transducer, pass it anywhere you would a transducer to get the bare step function behavior


clojure.set/index can be used to build more complex key/value lookup structures like a database index


Sometimes(usually for debugging) you just want to stick a function literal in the middle of a -> or ->>, this won't work like (-> ... #(f 1 % 2) ...) but will work like (-> ... (#(f 1 % 2)) ...)

✔️ 1

Loop/recur cannot be used to loop across a try/catch, trampoline is useful for retry loops on exception

👀 2

You can use (sort-by - ...) as a handy reverse sort in some cases, but not all, see for a complete write up on clojure (and java) sorting

👍 2

reducing for side effects is very nice, but as much as possible return some value from reducing, not just nil. Even just a count of reductions can be useful when debugging, testing, and logging.

👍 1

clojure.core/deref works on anything that implements clojure.lang.IDeref or java.util.concurent.Future, as a consequence of how that is implemented if you try to deref something that is not derefable, you get an error about casting to Future failing.

👍 1

tree-seq is for harvesting trees. it enumerates all the parts of the tree and you can keep want you want.

catjam 1

Calling str on a lot of clojure objects gives you a nice readable thing, but not on all clojure objects. Use pr-str instead

👀 1

proxy is really weird. In 10+ years I've never used update-proxy. And proxy-super is not thread safe(it mutates the proxy object).


A lot of metaprogramming kind of things don't even need macros, just intern


nice thread

John Bradens19:04:17

Is this an okay place to ask newbie hiccup questions? When I search for css & html help, I don't always know how to translate that to hiccup. For example, making an image bigger, or reducing padding somewhere, or centering text. I also get confused between what to edit: The hiccup in my cljs file, the css files, or my base.html


How are you using hiccup? do you inline styles with it as well?


FYI: There are a couple of webapps that translate html-to-hiccup if you have some HTML and want to just paste it in and see how it would look as hiccup syntax. e.g.

John Bradens19:04:08

@U01EFUL1A8M I think I'm using in-line styles... I'm following an example from ClojureBridge London. Here's a snippet where I have an image in the navigation bar that I'd like to make bigger (not sure if there's padding that's making it smaller):

(defn navigation-top
  ;; Navigation bar (responsive)
  [:nav {:class      "navbar is-fixed-top is-white has-shadow py-3"
         :role       "navigation"
         :aria-label "main navigation"}
   [:div {:class "container"}
    [:div {:class "navbar-brand"}
     [:a {:class "navbar-item"
          :href  "/"}
      [:img {:src "img/logo.png"}]]
     [:span {:class       "navbar-burger burger"
             :data-target "navbarClojureBridge"}
      ;; Empty spans needed for navbar burger
      [:span] [:span] [:span]]]
    [:div {:id    "navbarClojureBridge"
           :class "navbar-menu"}
     [:div {:class "navbar-end"}
      [:a {:class "navbar-item"
           :href  "/contact"
           :style {:font-weight "bold"}} "Contact"]]]]])

John Bradens19:04:44

@U05476190 Thanks! That's a great resource. I think now I'll feel a lot more comfortable googling html questions nkowing that I can translate them into hiccup

John Bradens20:04:47

I think with the navbar the problem is that there is padding around the image, but I don't know how to get rid of it. I'm using bulma, so would I have to go digging through the bulma file?


> not sure if there's padding that's making it smaller Forget about html vs hiccup for a minute; you really want to get more comfortable with Chrome and/or Firefox Developer Tools. That will help you answer those kinds of questions, quickly test alternatives, and find the source of what's causing the root issue (e.g. some bulma class, some padding, etc). IMO, that is time well spent and will save you a lot of grief in the long run. ;)

John Bradens20:04:17

Thanks!! I appreciate you pointing me in a productive direction

John Bradens20:04:44

Another question: For example, I want text within a div to be centered vertically. I did a google search and found

.center {
  margin: auto;
  width: 50%;
  border: 3px solid green;
  padding: 10px;
As an example. How would I add a css style margin: auto with hiccup?

John Bradens20:04:18

I'd prefer to stick to the hiccup files as much as I can instead of trying to change the css & html directly (Although I'd love to hear what best practices are?)


[:div {:style "margin: auto"} "Center Me"]
But you probably want to just do:
[:div {:class "center"} "Center Me"]
And then define the .center class in a CSS file


If you are looking for example projects, my landing page is written with ClojureScript, reagent and (actually it's mostly bluma)