Fork me on GitHub
#cursive
<
2022-10-21
>
Jared Langson16:10:37

Got a REPL question. I have anonymous functions defined in a let binding. When I try to send a piece of code inside the let binding to the repl it tells me that the var is undefined. I've used "Load File in REPL". Is there a way to use the repl with let forms? The code

(let [get-tile-values (fn [m n] (str (get-in m [:resources n]) " " (get-in m [:rolls n])))
        get-tile-css (fn [m n] (color-classes (str (get-in m [:resources n]))))]
    [:div.grid.grid-cols-5.gap-1
     [:div.text-white.text-center.p-2 (get-tile-values m 1)
      {:style {:class (get-tile-css m 1)}}]
;...
When I try to use the send X to REPL command it says it can't find the var. For example send (get-tile-values m 1) to REPL results in a "Use of undeclared Var front-end.views/get-tile-values" error message

imre16:10:46

send top form to repl

imre16:10:41

try that

Jared Langson16:10:02

Tried that and got the same error. I used send (defn map->grid) to repl. Running the functions declared inside the let binding gives the same error

imre16:10:49

try sending the entire let form

imre16:10:03

if there is no namespace-wide binding of get-tile-values then when you send (get-tile-values m 1) , clojure won't know what you mean by get-tile-values

imre16:10:13

or m for that matter

Jared Langson16:10:43

I manually loaded m into repl from a comment

Jared Langson16:10:07

sending the let form still doesn't let me use the methods declared inside the let

Jared Langson16:10:24

I can declare the functions globally, but that's a workaround

imre16:10:01

> sending the let form still doesn't let me use the methods declared inside the let you mean you send the let form and it errors out?

imre16:10:30

or you send the let form and then you try to send (get-tile-values m 1)?

Jared Langson16:10:21

the second. I can send the let form fine, but when I call the (get-tile-values m 1) it errors

imre16:10:41

bindings established in the let form are only available in the let form

imre16:10:22

that's why it doesn't work

Jared Langson16:10:44

I'm using the send at cursor function. Even though my cursor is inside the let form, it has no knowledge of the let form's binding?

(let [get-tile-values (fn [m n] (str (get-in m [:resources n]) " " (get-in m [:rolls n])))
        get-tile-css (fn [m n] (color-classes (str (get-in m [:resources n]))))]
    [:div.grid.grid-cols-5.gap-1
     [:div.text-white.text-center.p-2 (get-tile-values m 1)
      {:style {:class (get-tile-css m 1)}}]

imre16:10:26

yeah so when you say send let form, that will send your entire let form

imre16:10:48

but when from inside the let form you send (get-tile-values...) then it will literally send only that

imre16:10:57

that's akin to typing

imre16:10:07

`(let [myfn ...]

Jared Langson16:10:12

dang. What's the best way to use the repl for testing anonymous functions in let bindings? The only thing I can think of is declare them globally during development and move them into let for production

imre16:10:55

you can comment out the body of the let form and only make the body the form you want to evaluate in the scope of that let form

imre16:10:03

and then send the let form in

imre16:10:25

so (let [...] (get-tile-values m))

imre16:10:43

or you can go

imre16:10:13

(let [get-tile-values ...]
 (def get-tile-values get-tile-values)
...
)

imre16:10:15

and then

imre16:10:21

(get-tile-values m

Jared Langson16:10:31

Appreciate it. Thanks!

imre16:10:00

just make sure you don't check in the inline def

Jared Langson16:10:28

Super helpful. Thanks a lot 🙂

imre16:10:21

yw, good luck

apbleonard12:11:04

@U01ES0TF6V6 I've used this macro in the past for exactly this problem. In the repl you just make sure you have switched to the namespace of your editor, type (deflet []) and cut and paste the let bindings you want to "inline def" as its first argument (i.e. replacing the empty vector.) The macro will inline def them all for you so you can get on with the repling. Much quicker for large let blocks. https://gist.github.com/henryw374/5dfcbf9d27ec89b360058e81339cbe4e

❤️ 1
apbleonard12:11:46

When inline defing a lot it can be useful to "zap" the namespace a la https://clojurians.slack.com/archives/C0744GXCJ/p1667378949616179 :)

Jared Langson15:11:07

@U3TSNPRT9 with deflet, could it also work if I changed let to deflet in the function? And then I could change it back to let when I was done messing with it?

Jared Langson15:11:42

What's the advantage of zapping? I can reload the file and I can def the vars a second or third time. I tend to throw things in comment blocks so I can quickly reload useful snippets.

apbleonard17:11:09

Changing let to deflet might indeed work - never tried that! If you reload it won't "forget" anything previously "def'd". That's why to really clean up you have to "zap" or restart the repl. Reloading also doesn't drop other things like aliases you previously defined in your ns requires. Swapping aliases in your requires can similarly leave you unable to reload completely.