Fork me on GitHub
#beginners
<
2019-03-29
>
Patrick vd Glind19:03:21

Good day everyone

Patrick vd Glind19:03:39

Could someone help me with why having an nREPL is so powerful?

Patrick vd Glind19:03:16

and why other programming languages don’t have it

Patrick vd Glind19:03:54

from the interwebs I can see it allows you to connect to it with a client (VSCode in my case) and remote execute code

Lennart Buit19:03:52

yeah, its an instant feedback loop, I send code to my repl to “test” it the entire day

Patrick vd Glind19:03:29

thank you Lennart

Cameron19:03:33

@naxels I think first, Separate the concept of having a REPL from the concept of having a Network REPL Having a REPL is like having a workshop, you use tools in real time as you build, so as Lennart said - you get an instant feedback loop while you are constructing, rather than making changes, compiling etc NREPL is actually useful in many contexts, from editors to production code, anywhere you might want to send snippets of clojure to a remote REPL session. Sometimes the remote is just on your local machine and your text editor integration uses it to improve your dev experience. Sometimes the remote is a running instance of your production software and you want to issue control commands, inspect your software as it runs, or even hot swap code.

❤️ 4
Patrick vd Glind19:03:53

thank you Cameron

👍 4
Patrick vd Glind19:03:33

in learning Clojure, I use the REPL a lot, much much more than I did in Ruby/Go

joelsanchez19:03:33

locally, it provides a much faster feedback cycle, and in prod, it's an invaluable debugging tool

👍 4
Patrick vd Glind19:03:02

now that I use VSCode for Clojure, I was curious what the value of the nREPL was

Patrick vd Glind19:03:15

that is answered, i just need to learn how to work with it ha

Cameron19:03:34

Yeah, if you are just using the command line REPL, you have not experienced the real power yet

Cameron19:03:50

it's a full on development lifestyle with editor integration (which tends to use nrepl)

Cameron19:03:21

for instance, Calva for vscode can reload your file every time you save it

Cameron19:03:23

effortless

Patrick vd Glind19:03:33

i actually installed Calva

Patrick vd Glind19:03:41

and am curious how the reload your file works

Cameron19:03:46

it's a setting

Patrick vd Glind19:03:48

i did find the commands to Evaluate

Cameron19:03:03

you have to set it up in preferences > extensions > calva I think

Patrick vd Glind19:03:22

i think it’s called Eval on Save?

Patrick vd Glind19:03:31

(it’s on by default for me)

Cameron19:03:55

yeah that's it

Cameron20:03:06

so basically you need to have a repl started

Cameron20:03:09

in the terminal

Patrick vd Glind20:03:11

lots to learn ha

Cameron20:03:16

yeah, it takes time

Cameron20:03:27

but when it all clicks you'll live a better life

Cameron20:03:35

you need to make sure you have a repl up

Cameron20:03:37

are you using lein?

Patrick vd Glind20:03:47

yes i’m using lein and am connected to the nREPL

Cameron20:03:53

oh ok calva is connected?

Patrick vd Glind20:03:07

i get the feeling this is one of those things that ones you figured it out you never want to go back ha

Cameron20:03:21

in that case open a file, and use (in-ns '<your-namespace>)

Cameron20:03:24

in the repl

Cameron20:03:35

then you should be able to just define a var

Cameron20:03:38

(def whatever 1)

Cameron20:03:46

then in the calva repl terminal

Cameron20:03:50

eval whatever

Cameron20:03:14

I'm paraphrasing here too, I'd have to run through it all again to get it exactly right I'm sure 🙃

Patrick vd Glind20:03:22

do you know of a quick tutorial to get the hang of it?

Patrick vd Glind20:03:32

i tried the above, however doesn’t work for me

Patrick vd Glind20:03:56

(unable to resolve symbol error)

Cameron20:03:24

sometimes it's hard to figure out what is wrong with calva

Cameron20:03:39

try ctrl + a

Cameron20:03:45

ctrl + alt + v and e

Cameron20:03:48

to just load it all

Cameron20:03:52

and see if it outputs anything red

Cameron20:03:15

and you have to check the output terminal called 'Calva Says' sometimes too

Patrick vd Glind20:03:36

aaah i now also see that VSCode had already started a separate terminal for nREPL automatically labelled “Clojure REPL”

Patrick vd Glind20:03:50

i get errors on the namespace

Cameron20:03:38

yeah the Clojure REPL one is the calva repl connected to the nrepl

Patrick vd Glind20:03:40

i don’t see any message/output when i evaluate the file

Cameron20:03:49

is it green

Patrick vd Glind20:03:53

have a couple of println’s in tehre

Patrick vd Glind20:03:58

yes, the nREPL is green

Patrick vd Glind20:03:07

err orange/yellowish

Cameron20:03:21

you can paste a snippet here if you want

Lennart Buit20:03:13

haha, thats surprisingly dutch, you may be interested in #clojure-nl

Lennart Buit20:03:46

oh… already there

Patrick vd Glind20:03:54

haha yeah just found/joined the channel, are you Dutch?

Lennart Buit20:03:21

name shows it a bit, I guess

Cameron20:03:56

I thought you may have had a file open already

Cameron20:03:58

in a project

Patrick vd Glind20:03:10

i had a file open, but not in a project

Patrick vd Glind20:03:48

i found a free Clojure Udemy course i started to follow

Patrick vd Glind20:03:55

it didn’t mention anything about a project yet

Patrick vd Glind20:03:04

but i got VSCode & Calva setup

Lennart Buit20:03:06

read clojure for the brave and true!

Patrick vd Glind20:03:19

yeah i found that one

Patrick vd Glind20:03:56

thanks for your help guys! lot’s of learning ahead of me

Patrick vd Glind20:03:59

bought a couple of books

Patrick vd Glind20:03:04

want to learn Functional Programming

Cameron20:03:26

are you aware of Rich Hickey's talks?

Patrick vd Glind20:03:34

yes, watched quite some of those

Patrick vd Glind20:03:43

that’s one of the key reasons i came to Clojure out of the available languages

Patrick vd Glind20:03:59

like someone mentioned in a blog post, Rich Hickey is a ‘feature’ ha

🙂 4
😆 4
rich 4
mathpunk20:03:57

I wrote these functions, then realized: all data I'll apply artifacts to will have :results data, but not necessarily :screenshots or :logs. How can I rewrite this so that those values will be nil instead of throwing errors when I try and listFiles of nil?

(def ffilter (comp first filter))

  (defn artifacts
    [run-on-disk]
    (let [contents (.listFiles run-on-disk)
          result? (fn [f] (= "junitresults.xml" (.getName f)))
          screenshots? (fn [f] (= "screenshots" (.getName f)))
          logs? (fn [f] (= "logs" (.getName f)))]
      {:results (ffilter result? contents)
       :screenshots (.listFiles (ffilter screenshots? contents))
       :logs (.listFiles (ffilter logs? contents))}))

mathpunk20:03:48

(and open to other improvements! this is a lot better than what it's replacing but could be better)

mathpunk20:03:44

:thinking_face: I think I'm using ffilter in the wrong place, for one.... maybe I'll figure this out if I stare at it long enough

mathpunk20:03:26

is if-let called for maybe?

Lennart Buit20:03:33

having nil keys in a map is not very idiomatic

Lennart Buit20:03:47

its more idiomatic to just omit keys that are nil

Lennart Buit20:03:14

in that case, take a look at cond->

Lennart Buit20:03:18

also, while you are at it, there is letfn to define locally scoped functions

mathpunk20:03:54

this does seem closer:

(defn artifacts-2
    [run-on-disk]
    (let [contents (.listFiles run-on-disk)
          result? (fn [f] (= "junitresults.xml" (.getName f)))
          screenshots? (fn [f] (= "screenshots" (.getName f)))
          logs? (fn [f] (= "logs" (.getName f)))]
      (cond-> {:results (ffilter result? contents)}
        (ffilter screenshots? contents) (assoc :screenshots (.listFiles (ffilter screenshots? contents))))))

hiredman20:03:52

(group-by #(.getName %) contents)

mathpunk20:03:23

well I'm very happy to have finally made a cond-> work with

(defn artifacts-2
    [run-on-disk]
    (letfn [(results? [f] (= "junitresults.xml" (.getName f)))
            (screenshots? [f] (= "screenshots" (.getName f)))
            (logs? [f] (= "logs" (.getName f)))]
      (let [contents (.listFiles run-on-disk)]
        (cond-> {}
          (ffilter results? contents) (assoc :results (ffilter results? contents))
          (ffilter logs? contents) (assoc :logs (.listFiles (ffilter logs? contents)))
          (ffilter screenshots? contents) (assoc :screenshots (.listFiles (ffilter screenshots? contents)))))))

mathpunk20:03:31

but yes, group-by --- forgot all about it

Lennart Buit20:03:45

at least you learned something new along the way!

kaneko20:03:02

Hi everyone, I'm writing a function that takes a map and parses it into a sequence of api-calls (which are to be called later). I have something like this currently:

(defn parse-blueprint
  [blueprint]
  (when (check-keys blueprint)
    (let [[_ api-calls] (-> [blueprint []]
                                     (extract-draft)
                                     (extract-sections)
                                     (extract-quotes)
                                     (extract-lines)]
      (when-not (empty? api-calls)
        api-calls))))
The extract-x functions take in a map and a vector and returns the unmodified map and vector with new stuff appended. I'm wondering what the correct/idomatic way to do something like this would be?

noisesmith20:03:57

@naxels pardon if someone mentioned already, but a subtle key to why clojure's repl is so useful is that the language itself is designed so that iterated development in a repl can redefine things in a "flow" friendly way

noisesmith20:03:00

many languages have some sort of repl, with many of them the rules in the repl are subtly different from what works in source files, or there are key things you can't pull apart / examine / redefine in a repl

noisesmith20:03:18

clojure isn't perfect on this, but far ahead of most compiled languages

mathpunk21:03:54

hm, I'm not quite there yet --- this seems nice for the cases that have all the results, but I'm NPEing in the case where there's only :results---

(defn artifacts-4
    [run-on-disk]
    (let [contents (.listFiles run-on-disk)]
      (cond-> (group-by #(.getName %) contents)
        "junitresults.xml" (update "junitresults.xml" first)
        "logs" (update "logs" (fn [part] (.listFiles (first part))))
        "screenshots" (update "screenshots" (fn [part] (.listFiles (first part))))
        true (rename-keys {"logs" :logs
                           "screenshots" :screenshots
                           "junitresults.xml" :results}))))

mathpunk21:03:25

:thinking_face:

noisesmith21:03:44

you need something in (fn [part] ...) that deals with (first part) being nil

mathpunk21:03:29

huh. I thought that was covered by the first half of the line. I thought the update would happen if and only if there was something under that key

mathpunk21:03:10

maybe i'm holding cond-> wrong still? first time~

noisesmith21:03:52

hmm... you could be right

mathpunk21:03:53

ooooh I was thinking those keys would act like functions, but I probably have to do (fn [m] (m "screenshots"))

mathpunk21:03:43

current hypothesis: cond-> is only threading thru the 'action' half of the lines, not the 'assertion' halves

mathpunk21:03:20

is there a threading macro that hands the passed value to the condition as well as the action?

mathpunk21:03:44

(alas I gotta put this down for now but thanks for the direction)

noisesmith21:03:55

there's a version of cond-> that passes changes to the conditions from some library, can't recall precisely at the moment

mathpunk21:03:43

If I just bind that collection of partitions...

(defn artifacts-5
    [run-on-disk]
    (let [contents (.listFiles run-on-disk)
          m (group-by #(.getName %) contents)]
      (cond-> m
        (m "junitresults.xml") (update "junitresults.xml" first)
        (m "logs") (update "logs" (fn [part] (.listFiles (first part))))
        (m "screenshots") (update "screenshots" (fn [part] (.listFiles (first part))))
        true (rename-keys {"logs" :logs
                           "screenshots" :screenshots
                           "junitresults.xml" :results}))))

mathpunk21:03:09

I think there's still improvements but this looks like it fulfills the requirements

noisesmith21:03:28

ahh, the key "junitresults.xml" is always truthy

noisesmith21:03:33

that's your issue

noisesmith21:03:49

so yeah, looking it up in m fixes it