Fork me on GitHub

Hey, everyone! I’m new here, to Clojure, and to functional programming in general. I’m trying to wrap my head around how I should approach control flow in my Ring app in my request handlers and middleware as I’m fetching things from the database. Any tip for how I can improve these examples?


I feel like I’m possibly using these control flow macros in a way that makes the intent unclear or hard to follow


You can definitely simplify wrap-auth-session and avoid that nesting:

(if-let [user (some-> (get-in request [:cookies "sid" :value])
  (handler (assoc request :user user))
  (handler request))


You can remove the (do ..) wrapper in the first function -- you only have one expression in there so it's unnecessary to wrap in do. I don't think you can do much other simplification -- parameter access / validation in Ring handlers is always a bit verbose.


Not sure what you mean by "control flow macros" tho'...?


Thanks for the tips! I think some-> is perfect for what I was trying to achieve there. By control flow macros, I only meant things like do , if-let, if, and so on. Wasn’t sure what else to call them


They're special forms, technically, but we tend to just refer to them directly by their names. See When you say "macro" it has a very particular meaning in Clojure.

👍 1

(and, yes, it's a little blurred that a couple of the special forms are actually implemented as macros that expand to lower-level implementations: let in terms of let*, fn in terms of fn*)

👍 1
Ruy Valle03:08:44

Hello! Is there a way to add dependencies to deps.edn, get them from their repos and require them in a running clj repl?


There’s an experimental branch with support for this but it’s not part of clj yet

Ruy Valle03:08:35

also I am wondering if core.match supports matching nested lists. for instance given ('a ('b 1 2 3)) as input I would like to bind the list (1 2 3) to a pattern variable.

Ruy Valle03:08:29

I got it 🙂

Ruy Valle04:08:07

actually no I don’t


Are you looking for something like this:

user=> (match [['a ['b 1 2 3]]]
[[_ [_ & r]]] r)
[1 2 3]


Or if you really want sequential matching

user=> (let [x '(a (b 1 2 3))]
         (match [x]
           [([_ ([_ & r] :seq)] :seq)] r))
(1 2 3)


(I'm a bit puzzled by your ('a ('b 1 2 3)) example since that is not what you might think:

user=> ('a ('b 1 2 3))
Execution error (ArityException) at user/eval1600 (REPL:1).
Wrong number of args (3) passed to: clojure.lang.Symbol

Ruy Valle05:08:58

yes! thank you! I ended up doing what your showed in your second example

Ruy Valle05:08:39

and yes I should have written '(a (b 1 2 3))


(moved my question to a more appropriate channel)


I want to pass an expression or a name which binds to that expression to my macro. So I'm calling the macro like (m fn-name) and (m (fn [] ...)) instead of (m 'fn-name) . First, is this the right way to do it or should I always quote symbols when passing them to macros? Second, if it is the right way, then I can't figure out how to make the symbol expand in the original context (the code calling the macro) instead of macro definition context. When I try to macroexpand, it gives an error while trying to resolve the symbol in the wrong context, instead of expanding it.


macros receive lists and symbols, unevaluated


whatever the macro returns will be evaluated afterward


lists will become calls, symbols will be looked up - after the macro returns them


the only job of a macro is to take lists, symbols, etc, return a list (or rarely, just a symbol or whatever), so that the compiler can do the rest


'fn-name shows up to a macro as (quote fn-name) because the args are not evaluated before the macro sees them


the args to the macro don't expand in the context of the macro definition, they always expand in the context of the macro call


but, the macro can't see the run time value of a symbol - it can return the symbol, and the compiler turns that into code that looks up the value at run time


this isn't a good macro, but it establishes a point:

(ins)user=> (defmacro caller-x [] 'x)
(ins)user=> (let [x 0] (caller-x))


by returning the symbol x, it causes the compiler to emit code that looks up x

Michael W17:08:57

Hello, is there any book or other reading material on removing state? I seem to be addicted to state like it's crack. I have written and entire app in clojure that ties 6 different apis together, but I have state all over the place. I can't seem to wrap my head around getting rid of it.


the gist is to replace state with flow between simple machines. the talk had a lot to say about how this looks in the “large” (between multiple programs and servers), but also in the “small” (within programs)

Michael W18:08:01

I think I watched that before but I will watch it again.

phronmophobic18:08:38 is similar, but i usually don’t recommend it since clojure.core.async is usually overkill for most projects


but the principles are still useful even if you don’t use the library

Michael W18:08:22

Here is a simple toy I built that I ended up using as the basis of my app so you can see what I mean about addicted to state.


Hi guys, Can someone please explain what is the difference between these two snippets?


(map vec ’[(:a 1) (:b 2)])


(map vec [(:a 1) (:b 2)])


if I remove the quote the second line returns emtpy lists


The first quotes the vector expression, which prevents evaluating any of its contents


I thought quote is used only with forms


a vector is a form - everything the clojure repl can consume as a standalone value is a form


The second will evaluate the last expression


super, that makes sense


Evaluating a vector causes each element to be evaluated


thank you very much Andy


Quote can be used to prevent evaluation of any expression. It is not very useful to do so for expressions that evaluate to their own values like numbers and keywords, but it is not illegal

👍 1