Fork me on GitHub

(defmacro add-thread [s]
  (cons '-> s))
is I think what you want

Jordan Yee01:07:43

I thought that would be it, but I'm probably going about this all wrong. I have these macros:

(defn wrapper [m f]
  (f m))
(defmacro operation [f]
  `(wrapper ~f))
(defmacro expand-operations [m & ops]
  `(~m ~@(map (fn [op] (list `operation op)) ops)))
I'm effectively trying to insert the thread-first into the result of macroexpanding expand-operations.


does expand-operations do what you want it to do now?


what is the point of the operation macro?


and, like, why write a macro?


(and wrapper takes two arguments -- you're only giving it one argument in the operation macro)

Jordan Yee02:07:46

expand-operations doesn't do what my end goal is, so it may be the wrong approach. I'll back up. I have the following:

(-> request-data
  (operation-wrapper operation1)
  (operation-wrapper operation2))
operation1 and operation2 are functions that accept and return maps: request-data is an initial map. operation-wrapper is a function of the form (fn [m f]). It checks m for an error value, and returns m if an error is found, or else it executes (f m).

Jordan Yee02:07:49

I'm trying to write a macro, let's call it thread-operations that would produce the code above as follows: (thread-operations request-data operation1 operation2) So, (defmacro thread-operations [m & ops]) would be the definition.


don't write it as a macro, use reduce


(reduce operation-wrapper request-data [operation1 operation2 .. operationN]) like that?


Sorry, simplifying since operation-wrapper already accepts [m f]


Macros should generally be considered a "last resort". In real world Clojure, they're very rarely used.


Write everything with functions first, if you can (and you nearly always can), and then add a macro for "syntactic sugar" if necessary.

Jordan Yee03:07:17

Hmm, yes I think reduce is the answer here. I never use macros because I find I can do everything I'm trying to do without them, but as such, I've never learned them past the most basic concepts. I thought I finally found a case where they might be useful, but I guess not. Thanks for the advice!

Jakub Holý (HolyJak)10:07:04

Is there a Clojure(Script) screencast channel that focuses on live coding, so that I could watch & learn from more experienced people solving problems using Clojure? Something like but more recent? Thanks!

Jakub Holý (HolyJak)14:07:35

yes, clojure pills looks nice though not exactly what I imagined


I'd love to see the Clojure-equivalent of Edward Kmett's live coding sessions :- D


I thought about streaming my learnings on Twitch the other day. Just need to find time to get set up.

Bobbi Towers04:07:39

Thanks! I actually burst out laughing when I saw my channel posted here, since I'm pretty new myself and make videos primarily to document my own learning.


@U8LB00QMD they're fun so keep up the good (work) 😄


Hello all, is there any way to use dynamic predicate? Like (filter #(or <predicates-list>) collection)?

Jakub Holý (HolyJak)11:07:32

Perhaps (filter (fn [val] (some #(% val) predicates) col)?


There's some-fn

❤️ 4
Jakub Holý (HolyJak)12:07:13

Nice! I didn't know that one.


@holyjak -- there are lectures in these videos, but have you seen


What's the best way to make sure a program runs some clean up code at the end, before it exits?


There are component systems that have lifecycles…


Would using something like this be a bad thing?


there's java.lang.Runtime/addShutdownHook


What’s the best way to run bernoulli trials in clojure? I can do something like:

(defn bernoulli 
  (not (empty? (random-sample p [true]))))

(repeatedly 10 #(bernoulli 0.5))
But it seems like there’s probably a better way?


@torvaney (repeatedly 10 #(< (rand) 0.5))


Yep. That makes more sense. Thanks

👍 4

@holyjak have you taken a look at ? they do a joint repl programming session while explaining their work in the back half of every episode

❤️ 8
Jakub Holý (HolyJak)19:07:07

thanks! I guess that is what I have been looking for!


^ We may be having an episode in 1½ hours from now


Make a post if/when you do? I'd like to watch.

👍 8

@UANK2VBHA Looks like the episode is off for today (scheduling challenges)

David Reno19:07:25

Not really sure how to use doc with functions in other libraries. Trying to see the documentation for clojure.spec.alpha/gen, would have expected to type something like (doc :clojure.spec.alpha/gen), but that’s not working. Also tried to require…no joy:

user> (require '(clojure.spec.alpha))
user> (doc gen)


@dcreno (doc clojure.spec.alpha/gen)



(require '[clojure.spec.alpha :as s])
(doc s/gen)

David Reno19:07:35

I know I tried that, I wonder if I needed to require first?


You tried (doc :clojure.spec.alpha/gen) -- with a keyword argument.


(unless you typo'd it in your message)

David Reno19:07:15

tried both…


Yes, you must load a library first.

David Reno19:07:43

that’s it then, tried the right way but hadn’t loaded the library first.


doc reads metadata from the Var for the symbol -- so you won't see anything until the symbol is actually defined (which happens when you load the namespace).

David Reno19:07:52

does the library/file/class/whatever need to be downloaded to a particular location? I use lein but I don’t know where it downloads to and if it can always be loaded by the repl.

David Reno19:07:12

asking because

user> (require '[clojure.spec.alpha as s])
FileNotFoundException Could not locate clojure/spec/alpha/as__init.class or clojure/spec/alpha/as.clj on classpath.  clojure.lang.RT.load (

David Reno19:07:54

ah, that was an as instead of :as.


Everything downloads dependencies to your local Maven repository cache (in .m2 in your home directory -- but you should pretty much never need to look in there).


@dcreno there's two things going on here, that are combined in other toolsets but isolated here.


there's a directory where various dependencies are stored, and then a config that decides which versions and which ones are visible to your process


so, with most languages you do a global install, and that version of that lib is available to all processes


with maven based deps (which lein, boot, clj etc. all use), you have a shared cache that can have any number of versions of each dep, and a startup config that decides which versions of which deps are visible

David Reno20:07:30

Thanks for the background. Any further reading you’d recommend on this topic? Trying to understand differences between what lein ring server has access to (for a ring base app) and what I have access to in the spacemacs cider repl. Still a little fuzzy to me the process of getting files, loading files, referencing namespaces.


The leiningen docs might help. The basic idea is that project.clj decides which deps are looked for. If they are not already in the ~/.m2/repository/ cache they are downloaded (recursively for nested deps)


cider should see all the same deps if you point it at the right directory


but it's a per-process config, so if you started cider from a different project, or with a no-project bare repl, it won't see the same deps or at least not the same versions of the deps


so i was just reading about the reduce function which seems pretty great. An example was (reduce + [1 2 3]) to add the elements of the vector together. however, i can't figure out how to make this generic so that it would add up all the elements of a vector without knowing the initial size of it. any help on how i would do that or at least how i would look up and interpret the docs to learn how to do it myself?


you are likely looping over the vector index wise, instead of using a seq of the vector


seqs are like a functional version of an iterator, iterators have something like a hasNext method and a next method, seqs have first and rest


@chase-lambert I'm not sure if I understand that question - reduce already accepts collections that are not pre-counted, by producing a seq over them


so i was trying something like (defn sum-vector [[vector]] (reduce + [vector])) but i can't make that work. the best i've done is adding up 2 or 3 items from the front of the vector.


maybe i don't know how to say this will take a generic vector as a parameter or something super fundamental like that.


Try (defn sum-vector [vector] (reduce + vector))


You can then call that function as: (sum-vector [1 2 3 4])


If you would prefer a different definition that allows you to make calls like (sum-values 1 2 3 4), that can be defined, too, slightly differently.


lol! that totally works. i knew it was going to simple! oh man. so vector is an actual word that means generic vector doesn't it?


in a binding vector it shadows the actual meaning


it's a function that makes a vector out of some args, normally


vector is a parameter name that could be anything, e.g. (defn sum-vector [x] (reduce + x)) is the same function in behavior.


You could try calling it with (sum-vector 5), but it would give an error because (reduce + 5) is an error.


[x] doesn't mean "x is a vector", it means "take whatever x is, and put it in a vector"


i think i was putting extra brackets in making sure it knew it was a vector


right, see above


so if you have (def x [1 2 3]) [x] is [[1 2 3]]


but in an arg list [x] means "take the first element out fo this argument, and call it x"




You may wish to save destructuring for a later day of learning, perhaps.


(ins)user=> (defn weird-first [[x]] x)
(ins)user=> (weird-first '(1 2 3 4))
- right - it's a feature that was used accidentally here, I think


that's a good idea to just ignore it for now


but that's why your [[vector]] args were not an error - the compiler thought you were using the destructuring feature


ahh! destructuring. yeah i've already read that section of the Brave book 2-3 times. hasn't quite clicked yet.


(defn fn-name [x] <body of fn-name here> ) means to define function fn-name that takes exactly one parameter. Replacing [x] with [x y] would mean to define fn-name to take 2 parameters instead.


Those parameters can be values of any type, e.g. lists, vectors, numbers, strings. Clojure doesn't need (or usually even allow) to say what those types must be. The code in the body of the function definition often makes assumptions about what types of values it supports.


"but in an arg list [x] means "take the first element out fo this argument, and call it x" " that just cleared up some confusion for me.


i got a quick random question. when i'm playing around with set creation and such, my return value re-orders the items in the set. so (hash-set :a :c :d} becomes #{:c :d :a} and (hash-set 1 2 3 4) becomes #{1 4 3 2}. What is the implications of that? Is it something I should be considering when creating sets?


sets are not ordered


this also goes for hash-maps


so that means you shouldn't use them in code that relies on order of items in collections (but they are good for code where the question is "does this item exist in the collection")