Fork me on GitHub

Add a memoize and you're golden


See the Fibonacci example


(Although I don't think its entirely applicable to this, as you'd have to re-write it in a recursive manner)


I don't think memoizing factorial is actually helpful? I guess if you are calling factorial on a large number of small values it could help

Rob Haisfield00:05:02

Can you show me?


Why does -> expand to this particular result in this example?:

user => (macroexpand '(-> [1 2 3 4] (reverse) (drop 2)))
(drop (reverse [1 2 3 4]) 2)
the say that
the first form as the
second item in second form
I thought the first form was (reverse [1 2 3 4) and that it would be passed to drop as the second item (I expected)
(drop 2 (reverse [1 2 3 4]))


(drop 2 (reverse [1 2 3 4])) this is the form of three forms: drop , 2, (reverse [1 2 3 4])


Is thread first. It takes the result of the previous line and feeds it into the first argument position in the following form.
(-> [1 2 3 4]     ;; call this o
    (reverse)     ;; this line becomes (reverse o), o is in te second location in this form. This is evaluated and lets still  
                  ;; call the result o
    (drop 2))     ;; this line becomes (drop o 2)
Which obviously doesn't work. Rather than thinking of second position in the form, think of it instead as it makes the previous result the first argument in the next line.


You could use thread last in your example

(->> [1 2 3 4]
     (drop 2))
=> (2 1)
Now the result of each line is being fed into the final argument position in the following line.


Thank you @U013YN3T4DA. That’s what I thought, but the docs wording is confusing. Doesn’t saying

feeds it into the first argument position in the following form.
sound very different from what the docs say:
inserts the first form as the
second item in second form
if (drop 2) is considered the second form and o is the first form, isn’t the second item’s location drop 2 o (vs actual: (`drop o 2)` ). It makes sense the way you say it, but how I’m reading the docs, I’m still backwards


Consider the form a list, in the case of (drop 2 o), o is the third item in the list. In the case of (drop o 2),o is the second item.


I agree docs are confusing tho, i hardly ever go to docstring to understand a function


ohhhh that makes much more sense (considering it a list) now this doc line makes sense

making a list of it if it is not a
list already
Thank you Stuart

Joni Hiltunen11:05:42

If I'm correct, Leiningen doesn't have any "watch" support by default? If I would like to automatically rerun tests when files change for example


usually this is responsibility of a test runner. For example can “watch” for changed files and run subset of your tests affected but the change

Joni Hiltunen11:05:00

thank you both


There’s a lein-auto-test plugin I believe


Or lein-test-auto might be the name

Joni Hiltunen13:05:48

Thanks. I went with Kaocha, it was easy to set up and use

Rob Haisfield13:05:30

I love this video. Are there any other good example videos of people debugging and troubleshooting? One of the hardest parts about learning Clojure so far is that the error messages are basically written in Java and I don't know Java, so seeing more examples of troubleshooting would be great. Right now i feel like my only response to troubleshooting in a lot of cases is to ask someone for help.

👍 3

I'm trying to require inside a babashka script, (require '[ :as closh]) When I run, in the shell, bb ./file.clj I get:

----- Error --------------------------------------------------------------------Type:     java.lang.Exception
Message:  Could not find namespace:
Location: 3:1
At the same time, if I go to the closh shell, (sh ) autocompletes to


closh isn't the same as babashka


Could I interop them? I have a bunch of custom-written functions, and I'm struggling calling them. Basically, I have to eval one by one, right now. That's the underline thing I want to solve


If I can load the closh's macros inside babashka, that would be great


Feel free to join #babashka to discuss


Will do! Thanks for the invite


Is there any way to refer to clojure.lang.Keyword in a shorter form? I'm practicing multimethods for the first time and would like to dispatch on a class of keyword or number. Using Number works as expected, but Keyword doesn't seem to exist without the full name of clojure.lang.Keyword.


You could import the class via (import 'clojure.lang.Keyword)


Cool, that seems to do the trick. I tried using a [clojure.lang :refer [Keyword] , but that didn't work 😀


It looks like you are trying to required the class via the ns form. If so, try (ns my-ns (:import [clojure.lang Keyword])) instead.


That's even better, thanks a lot!

👍 3

I am trying to make an SPA based off of leiningen’s reagent template. They have the server set up so that all pages are handled by an index handler that mounts a loading page.

(defn loading-page []
   [:body {:class "body-container"}
    (include-js "/js/app.js")
    [:script "spotify_client.core.init_BANG_()"]]))

(defn index-handler
  {:status 200
   :headers {"Content-Type" "text/html"}
   :body (loading-page)})
I’d like to continue to use this handler for additional pages in my app because I need the script for core.cljs to run on all pages. However, I need to do some things (like make API calls, parse the response params from authenticating to the API, and returning a different response based on whether the user is authenticated) before returning a response map with an html body. Do I need to use a different handler? How do I go about integrating the new handler (if so) with the SPA template?

Rob Haisfield17:05:25

Why isn’t this working? Anybody who knows Specter that could help me out here?


all the :case1 entries are numbers, and MAP-VALS expects maps

Rob Haisfield18:05:24

Awesome, this worked:

(s/select [:employees ALL :case2] employees)

🎉 3
Rob Haisfield18:05:03

Is there some way to exclude stuff? I was looking for it in the documentation and struggling. See the bottom bit of code, which doesn’t work


I thought any function would work as a filter predicate


#(not= % :name)

Rob Haisfield19:05:10

Hmm that still doesn’t filter out the names

Joshua Suskalo19:05:01

So you want to select a set of keys that doesn't include name?

Rob Haisfield19:05:56

I want the output here to exclude :name 1, :name 2, etc. but keep all of the cases and their values. Desired output below.

Rob Haisfield19:05:19

[{:case1 600, :case2 800, :case3 1000}
 {:case1 1000, :case2 900, :case3 800}
 {:case1 800, :case2 700, :case3 700}
 {:case1 800, :case2 1000, :case3 1000}]

Joshua Suskalo19:05:36

(s/select [:employees ALL (s/view #(dissoc % :name))] employees)

Rob Haisfield19:05:17

Awesome. So if I understand this correctly, :employees ALL will take me to a map of all of the employee data, and then view allows me to apply the dissoc function to the resulting list?

Joshua Suskalo19:05:06

Yeah, basically. I'd make a key distinction that it doesn't take you to a map, but navigates you to every map. Specter is kinda weird in that it has ways to deal with "collections" but individually by way of navigation.


Is there some way to get better error messages? I'm editing a babashka script, running some things in my repl. I often get messages like: > clojure.lang.ExceptionInfo: No implementation of method: :as-file of protocol: #' found for class: clojure.lang.Keyword Is there some way to get line numbers or something in the error message?


@randumbo what is "my repl", is that JVM Clojure or babashka?


babashka should give you line numbers about this, or a nice stacktrace


it also has a REPL


@borkdude Babashka. Started it using :IcedInstantConnect babashka with it set to nrepl.


ah right, yeah in nREPL you don't get the errors you get when running it on the command line


Hmm, so I'd be better off using socket repl? I thought nrepl would be the preferred option as it returns data.


No, nREPL is fine, it just needs to do better on the error handling there I think. To explain the error though: When you call on a something, it tries to convert that something to a file. This conversion is implemented using a protocol called Coercions. But there is no implementation of that protocol for the Keyword type.


Long story short: does not accept keyword.


Yeah, I understand the error and can debug it, but without line numbers it's quite a hunt sometimes. Do you have some suggestions for getting better debugging hints when I run into situations like this?


@randumbo I think this is a specific issue with how nREPL is implemented in babashka: You should get better errors when you execute the script from the command line, so that might be the best debugging for now


bb 0.4.4 should now give a better error with the nREPL server


Thank you!


@borkdude fair enough, thanks very much.


Unrelated to my previous question.. I understand that doseq is basically for when I need to loop over something and produce side effects in the body. Is it weird that I often have nested doseqs when I need to iterate over an inner list?


Yes this is unusual


@randumbo doseq already supports multiple nestings


I’d like to add an item to a collection within a map and return the map with the new collection. If I use conj it’ll return just the collection. Is there an idiomatic way to update a collection w/i a map whilst returning the map? Thank you


@U01JYKT6ENL (update the-map :coll conj new-item)


🙌 thank you


Oh I didn’t know doseq allowed for nested bindings. Neat


you can arbitrarily mix & match further nesting, :when or :while clauses, and :let clauses


How do the nested doseq bindings work?


same as for basically


lol yes I've been staring at this page


@randumbo supposing you have a list of lists of numbers


(doseq [l z :when (> (count l) 3)
        n l :while (< n 5)]
  (println n))


z is the list of lists


that will iterate through the elements of z filtering out any that are shorter than 4


for each of those it will iterate through the numbers in that list and print them until it encounters one >= 5


same as what you're doing with nesting doseqs


Got it. I think I understand. Gonna refactor what I have to test myself. Thanks 🙂