beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
sova-soars-the-sora 2021-05-27T00:02:20.003600Z

Cool

sova-soars-the-sora 2021-05-27T00:02:33.003800Z

Add a memoize and you're golden

2021-05-27T20:09:05.047700Z

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

lsenjov 2021-05-27T01:00:17.005Z

https://clojuredocs.org/clojure.core/memoize

lsenjov 2021-05-27T01:00:33.005200Z

See the Fibonacci example

lsenjov 2021-05-27T01:02:30.005400Z

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

orpheus 2021-05-27T09:34:13.010400Z

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 https://clojuredocs.org/clojure.core/-%3E 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]))

2021-05-27T09:36:36.010700Z

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

2021-05-27T09:56:18.013300Z

->
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.

2021-05-27T09:58:03.013600Z

You could use thread last in your example

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

Joni Hiltunen 2021-05-27T11:51:42.015200Z

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

tvirolai 2021-05-27T11:56:00.015300Z

You can achieve this via lein-auto https://github.com/weavejester/lein-auto

2021-05-27T11:56:30.015600Z

usually this is responsibility of a test runner. For example https://github.com/lambdaisland/kaocha can “watch” for changed files and run subset of your tests affected but the change

Joni Hiltunen 2021-05-27T11:57:00.015900Z

thank you both

2021-05-27T13:12:30.019Z

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. https://youtu.be/lPczdxHt43g

👍 1
dpsutton 2021-05-27T13:20:33.019600Z

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

dpsutton 2021-05-27T13:20:52.020200Z

Or lein-test-auto might be the name

NoahTheDuke 2021-05-27T13:21:16.020400Z

i’ve had success with https://github.com/jakemcc/lein-test-refresh too

Joni Hiltunen 2021-05-27T13:21:48.020800Z

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

orpheus 2021-05-27T15:57:21.021700Z

Thank you @qmstuart. 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

2021-05-27T15:59:37.022300Z

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.

2021-05-27T16:00:29.022500Z

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

orpheus 2021-05-27T16:02:10.022800Z

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

BuddhiLW 2021-05-27T16:33:25.026400Z

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

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

borkdude 2021-05-27T16:34:36.026600Z

closh isn't the same as babashka

BuddhiLW 2021-05-27T16:36:26.028300Z

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

BuddhiLW 2021-05-27T17:05:57.029Z

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

raymond 2021-05-27T17:20:10.030900Z

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.

djblue 2021-05-27T17:21:42.031900Z

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

✅ 1
raymond 2021-05-27T17:23:15.033100Z

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

borkdude 2021-05-27T17:27:26.035200Z

Feel free to join #babashka to discuss

djblue 2021-05-27T17:28:42.036100Z

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.

Njeri 2021-05-27T17:41:15.042500Z

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 []
  (html5
   (head)
   [:body {:class "body-container"}
    mount-target
    (include-js "/js/app.js")
    [:script "spotify_client.core.init_BANG_()"]]))

(defn index-handler
  [_request]
  {: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?

2021-05-27T17:43:25.043Z

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

BuddhiLW 2021-05-27T17:45:28.043200Z

Will do! Thanks for the invite

phronmophobic 2021-05-27T17:54:17.043500Z

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

raymond 2021-05-27T18:02:17.043800Z

That's even better, thanks a lot!

👍 1
2021-05-27T18:08:24.044Z

Awesome, this worked:

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

🎉 1
2021-05-27T18:09:03.044300Z

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

phronmophobic 2021-05-27T18:20:40.044600Z

I thought any function would work as a filter predicate

phronmophobic 2021-05-27T18:21:13.044800Z

#(not= % :name)

2021-05-27T19:21:10.045Z

Hmm that still doesn’t filter out the names

2021-05-27T19:22:01.045200Z

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

2021-05-27T19:22:56.045400Z

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

2021-05-27T19:26:19.045600Z

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

2021-05-27T19:26:36.045900Z

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

2021-05-27T19:31:17.046100Z

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?

2021-05-27T19:32:06.046300Z

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.

2021-05-27T21:36:52.049200Z

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: #'http://clojure.java.io/Coercions found for class: clojure.lang.Keyword Is there some way to get line numbers or something in the error message?

borkdude 2021-05-27T21:38:18.049600Z

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

borkdude 2021-05-27T21:38:35.050100Z

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

borkdude 2021-05-27T21:38:51.050500Z

it also has a REPL

2021-05-27T21:40:08.051200Z

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

2021-05-27T21:40:47.051900Z

That's from vim-iced: https://liquidz.github.io/vim-iced/#_connecting_socket_repl

borkdude 2021-05-27T21:40:47.052Z

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

2021-05-27T21:41:22.052900Z

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

borkdude 2021-05-27T21:42:30.054300Z

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 <http://clojure.java.io/file|clojure.java.io/file> 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.

borkdude 2021-05-27T21:43:49.054900Z

Long story short: <http://clojure.java.io/file|clojure.java.io/file> does not accept keyword.

2021-05-27T21:44:51.056100Z

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?

borkdude 2021-05-27T22:05:36.056800Z

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

borkdude 2021-06-01T12:38:20.199Z

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

2021-06-02T09:22:50.235100Z

Thank you!

2021-05-27T22:06:10.057400Z

@borkdude fair enough, thanks very much.

2021-05-27T22:18:08.059Z

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?

borkdude 2021-05-27T22:19:14.059700Z

@randumbo doseq already supports multiple nestings

orpheus 2021-05-27T22:22:20.060900Z

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

dpsutton 2021-05-27T22:23:35.061500Z

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

blak3mill3r 2021-05-27T22:24:05.062100Z

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

2021-05-27T22:25:35.063Z

How do the nested doseq bindings work?

borkdude 2021-05-27T22:26:54.063300Z

same as for basically

borkdude 2021-05-27T22:27:34.063500Z

This website has some nice examples: https://clojuredocs.org/clojure.core/doseq

2021-05-27T22:28:05.063800Z

lol yes I've been staring at this page

blak3mill3r 2021-05-27T22:28:34.064100Z

@randumbo supposing you have a list of lists of numbers

blak3mill3r 2021-05-27T22:28:38.064400Z

(doseq [l z :when (&gt; (count l) 3)
        n l :while (&lt; n 5)]
  (println n))

blak3mill3r 2021-05-27T22:28:46.064600Z

z is the list of lists

blak3mill3r 2021-05-27T22:29:26.065300Z

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

blak3mill3r 2021-05-27T22:29:55.066Z

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

blak3mill3r 2021-05-27T22:30:39.066300Z

same as what you're doing with nesting doseqs

2021-05-27T22:35:41.067200Z

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

seancorfield 2021-05-27T22:53:43.067400Z

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

orpheus 2021-05-27T22:56:18.067600Z

🙌 thank you

ghadi 2021-05-27T23:20:20.068Z

Yes this is unusual