Fork me on GitHub
Justin Grahn03:05:40

Would someone be able to recommend a good walkthrough on testing in Clojurescript? I can’t for the life of me figure out how to require and run even the simplest tests from the REPL.

Rob Haisfield03:05:34

I’m really struggling to grasp reduce but every single example I see is just addition. Are there any really good, simple practical examples?


How about this:

user=> (reduce (fn [s w] (if (re-find #"[aeiou]" w) (conj s (first w)) s)) #{} ["the" "dry" "wind"])
#{\t \w}
Given a sequence of words, it produces a set of the first letters of any words that contain vowels.


To do that "long hand", you'd filter the words to just those that contain vowels, then map first across the result to get all the letters, then into #{} or similar to produce just the unique set of first letters.

Rob Haisfield15:05:55

Thank you for the string example!

Rob Haisfield04:05:29

So I have a function (check-code some-vector) that checks a vector against a bunch of rules. If they all return true, then the function returns true The screenshot I sent is code to generate x number of vectors of 5 digits. Then at the end, I want to filter it down to find just the results that are true Only problem is that this isn’t super useful How would I set it up to find the code vectors that returned the true value when they were passed in as an argument to check-code?

Lance Erickson04:05:40

I think you just want to take out the (map check-code call. Use (filter check-code (... instead. check-code can act as the predicate function for filter.

Lance Erickson04:05:22

When you map with check-code, you are applying a transformation and creating a new vector of booleans, where using filter will just admit any values that pass the predicate function unchanged.

Rob Haisfield04:05:52

That’s perfect, thank you


What is the canonical way to write this condition chain, without chaining if ?

(zero? ask-price)  then preMarketPrice, but if preMarketPrice is zero again then lastprice


try some-> or some


it can “short-circuit out” if result is not nil


but you will need to make few separate functions to obtain corresponding price and return nil if result is zero

Ivan Koz11:05:58

create a seq of all prices, choose first which is not 0 (some #(when (pos? %) %) prices)


but that will make (potentially) unnecessary side effects


(defn get-price []
  (http/request ...))

(def prices 

(some #(when (pos? %) %) prices)
like this

Ivan Koz11:05:13

wrap requests in a delay, make it lazy

Ivan Koz11:05:58

or fetch all prices at once, not even a problem is prices are parsed or queried from database


(defn get-price-1 [args] ...)

(defn get-price-2 [args]
  (http/request ...))

(defn get-price-3 [args] ...)

(some-> args (get-price-1) (get-price-2) (get-price-3))
this one ^ will not make http request if the result of get-price-1 is not nil

Ivan Koz11:05:13

why would anyone need 3 http requests to get 3 numbers


it depends, sometimes it might be required. I don’t think you understand completely the problem, do you?


also http request is just for illustrative purposes. It can be anything else - executing of db statement, fetching from file, asking user to enter price from stdin


anything that falls into huge space of IO operations

Ivan Koz11:05:09

again if laziness is a concern there is delay


the laziness is not a concern

Ivan Koz11:05:45

you just said: this one ^ will not make http request if the result of get-price-1 is not nil that is exactly about laziness and delayed evaluation


nono, it is about executing or not of some IO operations.

Ivan Koz11:05:14

Lazy evaluation, is an evaluation strategy which delays the evaluation of an expression until its value is needed.
So since some is a short-circuit operation, making source of lazy calls will not evaluate more than needed.


try this expression (first (map prn [1 2 3 4 5 6 7])) map returns lazy sequence, prn is doing side effects I expect it to print only one number but in reality it will print entire collection


only some-> can stop the chain (some zero? (map (fn [i] (prn i) i) [1 2 3 0 5 6 7]))

Ivan Koz11:05:45

(some #(when (pos? @%) @%) [(delay (side-effect 0))
                            (delay (side-effect 1))
                            (delay (side-effect 2))])
=> 1


right, but that implies a certain interface for every element in a sequence


Thanks guy. I enjoyed both your solutions


Cool trick with some-> @U04V4KLKC !


pattern matching : )


Personally I’d write a function like (defn non-zero [n] (when-not (zero? n) n)) and then it’s just (or (non-zero ask-price) (non-zero preMarketPrice) lastprice)


But for an isolated case I don’t think there’s anything wrong with nested ifs, either


And it looks like something that might be applicable in different situations, so it might worth speccing it and that opens up possibilities with regard to default value handling


Pattern matching feels like overkill and not overly functional : )


but it's extensible : D you can add further conditionals later : D


hi, how would you refactor this handler function to be more idiomatic?

(fn [request]
             (let [todo-list (:body-params request)
                   conn (db/db-connection!)
                   saved-todo-list (db/insert-todo-list! conn todo-list)
                   _ (db/close! conn)]
               {:status 201
                :body   saved-todo-list}


you could create a wrapper similar to with-open to open connection, do something with it and close at the end.

(defmacro with-open-conn [[conn open-expr] & body]
  `(let [~conn ~open-expr]
       (do [email protected])
       (finally (db/close! ~conn)))))

👍 1
Joni Hiltunen12:05:22

New to everything... Is it possible to use spec to say that if one thing is X then other thing must be Y or else etc... Hard to explain, I have a gist

Joni Hiltunen12:05:38

Hmm, that might be it.. Just need to figure out how to use it 😄


(defmulti by-command (fn [[command _]] command))

(defmethod by-command :move [_]
  (s/tuple ::command ::move-arguments))

(defmethod by-command :turn [_]
  (s/tuple ::command ::turn-arguments))

(defmethod by-command :repeat [_]
  (s/tuple ::command ::repeat-arguments))

(s/def ::instruction (s/multi-spec by-command :instruction))
something like this should work

Joni Hiltunen12:05:13

thank you for the example!

Joni Hiltunen12:05:38

tbh I didn't fully understand the multi-spec thing but I managed to do what I wanted with s/or... (I think)

Joni Hiltunen13:05:00

I wonder if there's already a function that does this?

(defn run-script [turtle [instr & script]]
  (if instr
    (recur (step-turtle turtle instr) script)

Joni Hiltunen13:05:11

ahh.. that's reduce I think

☝️ 1

Hi, what would be the Wordpress of Clojure?

Jeff Evans16:05:16

Suppose I want to use partition-by, but I want the logic to depend on some already seen values (not only the “next” value). Do I need to implement my own via reduce?


that would be the simplest thing - either reduce or a function using lazy-seq surrounding a self call to build the values


(defn filter-weird
   (filter-weird #{} coll))
  ([seen [x & xs :as coll]]
    (cond (empty? coll)
          (contains? seen (inc x))
          (filter-weird seen xs)
          (cons x
                (filter-weird (conj seen x)
user=> (filter-weird (range 10 0 -1))
(10 8 6 4 2)
@jeffrey.wayne.evans - I totally spaced the "partition" thing, but it's a simple demo of having a state accumulator (as you would in reduce) inside a lazy function

Jeff Evans16:05:28

could also do it as a stateful transducer, I suppose


yeah - these recursive lazy-seq building idioms are straightforward to build as a transducer - the main question I guess is whether laziness is useful in your use case

Jeff Evans16:05:03

yeah not so much

Jeff Evans16:05:09

the “real application” is for tiny structures

Jeff Evans16:05:40

and just have the fn passed to partition-by accept two args

Joni Hiltunen16:05:20

This isn't quite reduce is it? I wonder if there's a function for this

(defn- repeat-turtle
  [turtle [n subscript]]
  (loop [i 0
         res turtle]
    (if (>= i n)
      (recur (inc i) (run-script res subscript)))))


it's iterate plus a side effect (which means clojure.core/iterate isn't safe for this kind of usage I think)

Joni Hiltunen16:05:26

there isn't a side effect. run-scriptis a function of type turtle -> script -> turtle

Joni Hiltunen16:05:46

(defn- repeat-turtle
  [turtle [n subscript]]
  (last (take (inc n) (iterate #(run-script % subscript) turtle))))
this seems to be equivalent... is there a better way than (last (take ..))?


(-> turtle
    (->> (iterate (fn [step]
                    (run-script step subscript))))
    (nth (inc i))) 

Joni Hiltunen17:05:44

right.. nthlol 😄 thanks


if you flip the args to subscript you can use partial:

(-> turtle
    (->> (iterate (partial flipped-run-scropt subscript)))
    (nth (inc i)))


(read-string "(rf/dispatch [::events/some-event 1])")

=> Invalid token: ::events/some-event
Anyone know what I need to provide so read-string doesn’t throw here? I’m not sure which opts read-string takes, some Java Object opts down in the clojure.lang.RT class. I’m thinking I need to do something with a wrapping (bindings form?


there isn't an option you can provide to read string


when reading keywords with '::' the namespace part is resolved against the value of *ns*


so what you would have to do is create namespace, add an alias to that namespace for events, then bind *ns* to that namespace, and call read-string


dang, ok. just to expand on what I’m trying to do, ::events is imported at the top but read-string doesn’t ‘ingest’ that so to speak.. fuller example:

(read-string (str "[(ns  (:require [ :as events]))\n\n"
                    "(rf/dispatch [::events/some-event 1])]"))
so I guess I’d have to like, use regexes to read the imports and construct the lookup map with aliases for the reader?


ok, this worked

    (create-ns '
    (alias 'events '
    (read-string (str "[(ns  (:require [ :as events]))\n\n"
                      "(rf/dispatch [::events/some-event 1])]")))


what are you trying to do? why problem are you solving?


I have a build step that generates a routes.cljs file based on what is in the pages directory of the app


part of that is reading in those files and parsing out a few things


if you ditch the reader expanded aliases it might be easier. how much benefit do you get from vs :event/some-event?


I was looking for something like that


I actually want it to not care


the reader will always care if you ask it for "some-event from the thing called events". but if you are using read-string why not just put those files on the classpath and require them?


great question….


well, the script is clojure but the files are clojurescript


the whole thing is pretty messy, I don’t want to hold y’all up and I really appreciate the tips, I’m going to work on adding aliases from the (ns form in each file iteration


Scratch that :)

Erik B Good19:05:34

Hello again, I am once again hitting a wall with what seems like a pretty easy situation. Given an arbitrary nested sequence, I want to recreate it with the same nested structure. I am able to do it fairly easily with normal recursion, but I was wondering whether anyone could think of an answer using (recur). I am surprised how hard it can be to convert a recursive function to the loop/recur construct in some context.. (= [1 2 [3 [4 5] 6] 7] ((*fn* recreate-struct [ds recreated-ds] (*if-not* (instance? clojure.lang.Seqable ds) (conj recreated-ds ds) (into recreated-ds (map #(*if-not* (instance? clojure.lang.Seqable %) % (recreate-struct % recreated-ds)) ds)))) [1 2 [3 [4 5] 6] 7] []))


sorry, that’s not super helpful but if you weren’t aware of that namespace it’s awesome


for nested sequences, I'll often use A common starting point is:

(defn clj-zip [obj]
  (z/zipper #(and (seqable? %)
                  (not (string? %)))
            (fn [node children]
              (if (map-entry? node)
                (vec children)
                (into (empty node) children)))
you can emulate prewalk with:
(defn zip-walk
  "Depth first walk of zip. edit each loc with f"
  [zip f]
  (loop [zip zip]
    (if (z/end? zip)
      (z/root zip)
      (recur (-> (z/edit zip f)
it's pretty easy to also emulate postwalk and I find it a little more flexible than clojure.walk example usage:
(-> {:a 2
     :b [3 4 5]
     :c {:d 10}
     11 12}
    (zip-walk (fn [x]
                (if (number? x)
                  (inc x)
;; {:a 3, :b [4 5 6], :c {:d 11}, 12 13} 

Erik B Good19:05:25

Alright I will talk a look into these two namespaces at once. Thanks both of you dearly for your help


you may also be interested in something like specter,


Does anyone use clojure in wsl with intellij can help me with REPL?


You might try the #cursive channel.

Ian Fernandez19:05:44

Hi, where can I ask about Compojure

Ian Fernandez20:05:58

there's some default middleware to assoc the request to a system-configuration ?

Ian Fernandez20:05:07

or something like this?

Ian Fernandez20:05:25

to make something like a context that interceptors have


Can you explain in a bit more detail what problem you’re trying to solve?


What do you mean by “system-configuration”?

Ian Fernandez20:05:05

I have a default configuration for the things that are external from my system, then I need to start connections and etc, this "started-config" is what I call a system. I want to make my handlers dependent from my system


(defn wrap-config [handler config]
  (fn [req]
    (handler (assoc req :system/configuration config))))
That would be all you’d need to add a data structure to the request.

Ian Fernandez20:05:40

that's what I thought when I was talking here hahahah

Ian Fernandez20:05:57

sorry about ruber-ducking here


hi, I'm using monger and specifically the function find-maps this way

(let [conn (connect-with-credentials <.....>)]
                 (find-maps (mg/get-db conn "todo-lists") "collection")
                 (finally (disconnect conn))
it seems find-maps already closes the connection so I get an error in the finally


this seems to be inconsistent with the other function find-one-as-map that doesn't close the connection. It seems this feature has been introduced with not sure why