Fork me on GitHub
#beginners
<
2021-05-27
>
sova-soars-the-sora00:05:33

Add a memoize and you're golden

lsenjov01:05:33

See the Fibonacci example

lsenjov01:05:30

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

noisesmith20:05:05

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?

orpheus09:05:13

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]))``

delaguardo09:05:36

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

Stuart09:05:18

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

Stuart09:05:03

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.

orpheus15:05:21

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

Stuart15:05:37

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.

Stuart16:05:29

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

orpheus16:05:10

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

tvirolai11:05:00

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

delaguardo11:05:30

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 Hiltunen11:05:00

thank you both

dpsutton13:05:33

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

dpsutton13:05:52

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

👍 3
BuddhiLW16:05:25

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`

borkdude16:05:36

closh isn't the same as babashka

BuddhiLW16:05:26

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

BuddhiLW17:05:57

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

borkdude17:05:26

Feel free to join #babashka to discuss

BuddhiLW17:05:28

Will do! Thanks for the invite

raymond17:05:10

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.

djblue17:05:42

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

3
raymond17:05:15

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

djblue17:05:42

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.

raymond18:05:17

That's even better, thanks a lot!

👍 3
Njeri17:05:15

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

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

phronmophobic17:05:17

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

phronmophobic18:05:40

I thought any function would work as a filter predicate

phronmophobic18:05:13

`#(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.

Buidler21:05:52

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?

borkdude21:05:18

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

borkdude21:05:35

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

borkdude21:05:51

it also has a REPL

Buidler21:05:08

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

borkdude21:05:47

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

Buidler21:05:22

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

borkdude21:05:30

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.

borkdude21:05:49

Long story short: does not accept keyword.

Buidler21:05:51

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?

borkdude22:05:36

@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

borkdude12:06:20

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

Buidler09:06:50

Thank you!

Buidler22:05:10

@borkdude fair enough, thanks very much.

Buidler22:05:08

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

borkdude22:05:14

@randumbo `doseq` already supports multiple nestings

orpheus22:05:20

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

seancorfield22:05:43

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

orpheus22:05:18

🙌 thank you

dpsutton22:05:35

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

blak3mill3r22:05:05

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

Buidler22:05:35

How do the nested doseq bindings work?

borkdude22:05:54

same as `for` basically

Buidler22:05:05

lol yes I've been staring at this page

blak3mill3r22:05:34

@randumbo supposing you have a list of lists of numbers

blak3mill3r22:05:38

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

blak3mill3r22:05:46

z is the list of lists

blak3mill3r22:05:26

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

blak3mill3r22:05:55

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

blak3mill3r22:05:39

same as what you're doing with nesting `doseq`s

Buidler22:05:41

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