Fork me on GitHub

ahn, it is possible to add the implementation using extend

(extend Value
  {:isEmpty (fn [this] "ok")})


both .isEmpty and isEmpty are available.


Awesome. Thanks

Baibhav Bista06:06:51

Hello guys, I wrote a beginner-friendly walkthrough for getting a Clojure environment setup on Windows. Would love feedback, especially from learners who go through this to get their environment set up.


I quite like it. I'll give it a go once I'm on my Windows box. Btw do you mind if I take it as an inspiration to write similar guide but without WSL?

๐Ÿ‘ 1
Baibhav Bista06:06:28

If you have any suggestions, feel free to comment in the doc itself or message me


is there a common pattern for dealing with legitimate nil return values, which might mean error in a context? i found myself writing these quite often, but seems awkward (if-let [ret (fn-with-legitimate-nil)] ret (throw (ex-info "too bad" {:type :mine})))


(doto (fn-with-legitimate-nil) (assert "too bad"))


(doto (fn-with-legitimate-nil)
  (when-not (throw (ex-info "too bad" {:type :mine}))))


thank you! would you say is this โ€œidiomaticโ€ even there is no interop?


doto is a good fit when the return value is ignored, not only for interop


I'm not sure this pattern is idiomatic, but it's rather popular

๐Ÿ‘ 1
Timur Latypoff07:06:02

Funny thing I noticed, for simple cases (for ...) is faster than (map ...).

(time (when-let [x (into [] (for [i (range 20000000)] (* i 2)))] (count x)))
"Elapsed time: 1716.010281 msecs"
=> 20000000
(time (when-let [x (into [] (map #(* % 2) (range 20000000)))] (count x)))
"Elapsed time: 2346.677037 msecs"
=> 20000000
(time (when-let [x (mapv #(* % 2) (range 20000000))] (count x)))
"Elapsed time: 1367.96382 msecs"
=> 20000000
So looks like it's both more legible (for newbies like me) and faster than intricate map/`filter` combinations ๐Ÿ™‚

Vincent Cantin14:06:49

it will be faster with a transducer

Matheus Moreira07:06:45

hello, all! i am reading about transducers ( and and iโ€™d like to confirm something: when i comp transducers is it correct to say that the operations are applied in the inverse order we usually have resulting from comp? e.g. if i (comp str +) then + comes before str but if i (comp (map inc) (filter odd?)) then inc happens before odd?.

Vincent Cantin14:06:58

if you are interested, there are other articles about transducers at

David Pham07:06:26

Yes. You can think of comp as -> for transducers

๐Ÿ‘ 1
David Pham07:06:08

The reason is a (map inc) returns a transducer. I would recommend watching the transducers talk from Rich Hickey from strangeloop to understand why.

๐Ÿ‘ 1
David Pham07:06:28

In short: (map inc) returns a function which accept another function as input, but the process is done the inverse order. (You could make an analogue with middlewares if that helps).

Matheus Moreira07:06:40

cool, thanks! i was having a hard time trying to understand the texts because the results usually were different from my mental calculations. today i took some time to textually expand the composition and see what was going on and then wanted to confirm that it was indeed the -> order instead of the usually expected comp order. ๐Ÿ™‚


If we're a little pedantic (sorry ๐Ÿ˜…), comp works normally with transducers. Think middleware that transform HTTP request handlers. IF you take two of these A and B, comp them and then transform a handler with that and use it. B will be passed the handler, and the returned handler will be passed to A, which itself returns a handler, which is used. Now, if both A and B are middleware that add headers a and b respectively, then when a request comes in, header a gets added first and then b gets added. Hope this helps.

Matheus Moreira07:06:51

iโ€™ll check the talk.

David Pham08:06:44

You might to watch the Clojure reducers talk as well (the one where he talks about apple pies). Which is a bit of the foundation I heard.

๐Ÿ‘ 1
Mark-James M.19:06:36

Is there a reason why you do (conj a-vector value) but (cons value a-vector)? To preserve the order?


I do not know if the answer to that particular question can be found at this FAQ on argument order in Clojure core functions, but probably worth reading:

๐Ÿ‘ 1

For cons , the Scheme/Common Lisp function of the same name may have been an influence on arg order there.


yeah, that's my first hunch as well


conj is a collection function and adds a value at the "appropriate" (fast) place for the specific collection type. cons is a sequence function and always adds a value at the start of the sequence (which is always O(1)).

๐Ÿ‘ 1

(conj [1 2 3] 4) produces a vector. (cons 1 [2 3 4]) produces a sequence (technically a Cons cell with 1 as the first element and (seq [2 3 4]) as the rest of the elements).


is seesaw still a lib which should be used today? I'm trying to go with a tutorial and ran into: "Tried to use insecure HTTP repository without TLS:" while running Leiningen to fetch the dependencies.


you shouldn't need any non-default repositories to use seesaw


@sroller What does lein version report? Wondering if you have an old version of Leiningen that's still using http links...


Leiningen 2.9.3 on Java 13.0.1 OpenJDK 64-Bit Server VM I read I should downgrade to 2.9.1 which wouldn't be as "picky" with http/https.


Ha, I switched to seesaw 1.5.0 and the problem went away.


I'm using memoize ... but I get [email protected] instead of a result


ohhh oh oh oh just DEF not DEFN

parrot 1