Fork me on GitHub
#beginners
<
2020-09-21
>
Jim Newton07:09:29

Didn't I read somewhere that the clojure reader is side-effect free? or am I remembering wrong?

sogaiu07:09:09

i think one can define a tagged literal that when read can invoke a function you get to decide the definition of... https://clojure.org/reference/reader#tagged_literals

sogaiu07:09:44

> The data reader function is invoked on the form AFTER it has been read as a normal Clojure data structure by the reader.

sogaiu07:09:27

perhaps you are thinking of there being no user-definable reader macros?

Risetto08:09:31

If I want to cause a side effect, and return a value from a function do I have to use let? I don't need to let anything so it feels wrong to use for that purpouse

delaguardo08:09:22

why not to call side effect function directly, without wrapping in let? could you give an example

bartuka09:09:32

as I understood, you want to do something like this:

(do
  (side-effect-fn)
  (desired-value-from-fn))
but an example would be great o/

☝️ 3
Risetto12:09:00

You are right. For whatever reason I thought do only did side effects while not returning anything

😉 3
borkdude10:09:23

Don't know if this is something beginners are interested in, but I just created the #pr-welcome channel where people can post little things to work on on a project that are possibly also interesting for beginners

aw_yeah 6
lambdalove 9
kimim12:09:10

Hi all, is there a good way to chain to filter to a collection. For example if I have a vec with several filter functions [filterfunc1 filterfunc2]. I want to apply these filters to the collection [{...} {...} ...], and returning the {...}s match the filter functions.

delaguardo12:09:46

https://clojure.org/reference/transducers#_defining_transformations_with_transducers have a look at transducers

(sequence
  (comp (filter fn-A)
        (filter fn-B))
  collection)

kimim12:09:34

Thank you delaguardo, I will try this tomorrow morning.

jsn13:09:37

Why not just (filter (every-pred fn-A fn-B fn-C) coll) ?

delaguardo14:09:05

facepalm how could I forget about every-pred ? too much transducers happen in my code recently(

teodorlu07:09:37

Another line of thinking: reduce over your list of filters. Relevant if you need to control how filters are applied.

kimim07:09:06

[fn-A fn-B fn-C] is in a vec, is it possible to use (every-pred [fn-A fn-B fn-C]) this way?

delaguardo07:09:11

Yes, it is possible, but via apply. (apply every-pred [fn-A fn-B fn-C])

kimim07:09:49

Great, Thank you.

Panagiotis Mamatsis14:09:14

Hi everyone. I have started my journey to Clojure using the book Clojure for the Brave and True. Wow! It's completely different than any other language I have used upto now! I have a question to ask. Is Clojure suitable for building web applications?

João Galrito14:09:43

Welcome! I started recently as well. I believe Clojure/ClojureScript is well suited for web development. You've got Ring on the Clojure side for web servers and Reagent, Re-frame, Figwheel on Clojurescript side for front-end development

Walt Stoneburner14:09:31

I'm certainly not an expert on the matter, but from a "beginner" perspective, I've been able to set up a web server, do templating, create routes, handle concurrent sessions, and even do some pretty wicked stuff with websockets. So Clojure appears more than capable in this matter. ... in fact, it was much easier than doing it with other languages.

schmee15:09:02

Clojure is an excellent language for web development! and it can be used both in the backend and in the frontend via Clojurescript :thumbsup:

practicalli-johnny17:09:27

Yes, I've been writing a free book (with videos) on Clojure web apps and api's. https://practicalli.github.io/clojure-webapps/ There is also the commercial book on Web Development with Clojure https://pragprog.com/titles/dswdcloj3/web-development-with-clojure-third-edition/

Test This14:09:50

@U014818PP8S What do you use for websockets? Which routing library and server are you using? Thank you.

practicalli-johnny15:09:09

Compojure is the most common library for routing on the server side. reitit is a new project that takes a data driven approach to routing and other aspects of webapps. Its very interesting, but has more of a learning curve. Http-kit can do we sockets, although not something I've used recently

Walt Stoneburner17:09:44

@curiouslearn, I'm using aleph.http/websocket-connection ... I had to do a little fiddling, though.

Test This19:09:03

Thank you @U05254DQM. Appreciate the input. Also, thank you @U014818PP8S. Will look into it; although it looks difficult; I have no idea what a manifold is.

practicalli-johnny21:09:18

Manifold is a very interesting approach, especially when you dont want to be tied to the classic web server approach. However, there is more of a learning curve compared to ring and compojure. If you are creating API's then there is the compojure-api, https://github.com/metosin/compojure-api/ which includes swagger for documenting the API automatically. Luminus is a very useful template for web apps and full stack apps https://luminusweb.com/

Test This23:09:53

@U05254DQM, thank you very much for the pointers. I bought the second edition of the Luminusweb book a couple of years ago. However, it has too much magic for my taste. I usually don't like when lot of files are created for me in the source code. Will look into compojure-api. But so far reitit with http-kit seems a good option. I hope that http-kit continues to be maintained.

practicalli-johnny10:09:18

http-kit just had a new release and the maintainers that took over the project seem very motivated. If using reitit, be aware its fairly new so may not have as many examples documented. Suggest asking questions in the #reitit channel if you cant seem to find the help you need.

jmayaalv09:09:29

there are also a couple of curses online. can’t recommend enough: https://www.learnreagent.com https://www.learnreframe.com https://www.learnreitit.com

Walt Stoneburner14:09:51

Hopefully this is a simple question -- while reading some intro-Clojure materials, it basically said something along the lines of: If you're going to make a global variable, add ^:dynamic, and don't forget the earmuffs. My specific need involves something along the lines of a shared data structure between threads of web server connections. That "global variable" is really only local to that one modules and is only "modified" by exported functions. (Should I take the earmuffs off; yes, I realize it's only a convention, but I'd like to "communicate" the right thing to readers.) And, as I learn more about the dynamic metatag, this appears to be about the behavior of re-binding, which I'm not doing -- so is it even needed? The variable itself is nothing more than an atom wrapping a map, keeping track of things as sessions come and go. I'm now inclined to think a regular old def is all I need, but wanted to hear it from folks far more experienced than I.

João Galrito14:09:59

you want dynamic vars when you are rebinding the symbol itself to a new value, in your case if you're using an atom you don't need a dynamic var

João Galrito14:09:22

also the syntax of working with atoms already force you to treat it differently (with deref/@)

👍 3
Walt Stoneburner14:09:10

Fantastic - - that's what I suspected. I'm always leery of "generic advice" that doesn't take into account the problem being solved; I suspect the material I had read was just trying to explain re-binding examples.

schmee15:09:26

agree, remember that dynamic and mutable are not the same thing in clojure: there are many way to get mutable data (atoms, refs, agents), and a dynamic var is one of those ways :thumbsup:

manutter5114:09:20

Building web apps in Clojure is what I do for a living @pmamatsis

Panagiotis Mamatsis14:09:48

@manutter51 Really??? Wow! That's great! My end goal is to use Clojure for web applications! Meaning that there are web frameworks for Clojure?

Panagiotis Mamatsis14:09:46

But how Clojure is handling the load? I mean, in comparison with other languages (eg. BEAM based ones) which are using the actor model? My question is purely out of curiosity...I am a JVM guy (Java, Groovy and a bit of Scala)

João Galrito14:09:03

I haven't looked into the web side of clojure/clojurescript yet but I'm looking forward to it

manutter5114:09:38

Clojure’s approach is more library-oriented than framework-oriented, meaning there’s not really a “Clojure-On-Rails.” Ring and Compojure are a couple popular libraries providing basic server and routing functionality, etc.

👍 9
Panagiotis Mamatsis14:09:29

@manutter51 Oh I see! I don't mind! I want to also start thinking like a Clojure guy. But I am wondering about the heavy load in the back-end.

manutter5114:09:16

I had similar concerns when I first started, but so far I’m not seeing any load-related problems. Plus there are libraries you can add in to support spinning up X number of load-balanced servers in the cloud, so there’s no theoretical limit to how big a load a Clojure-based web app can handle.

Panagiotis Mamatsis14:09:27

@manutter51 you mean container based approach, right?

manutter5114:09:31

Yeah. It’s not something I’ve ever needed to work with, but it’s out there.

manutter5114:09:19

http://Heroku.com supports Clojure for deploying web apps over AWS, for example.

Panagiotis Mamatsis14:09:42

@manutter51 and @U014818PP8S really appreciate your replies. I will continue my journey into Clojure.

valtteri15:09:58

Usually perf is not the only measure you need to take into account. However, Clojure can be as performant as any other JVM language. Here’s a good video about perf-related aspects in Clojure web-dev if you’re interested https://www.youtube.com/watch?v=3SSHjKT3ZmA&amp;t=4s&amp;ab_channel=Metosin

valtteri15:09:50

There are many components involved in web development that affect the overall performance. The language itself plays some minor role there. It’s more about the libraries, IO, the type of load etc..

Michaël Salihi16:09:08

@pmamatsis As @manutter51 says, Ring and Compojure are very great to begin. You can check this very well documented repo: https://github.com/seancorfield/usermanager-example/

seancorfield16:09:02

@pmamatsis We support 40+ online dating sites in a dozen languages with a global customer base using all Clojure on the backend -- performance is great for that. And that's without doing "anything special" to improve performance.

Panagiotis Mamatsis17:09:45

Wow!!! Really appreciate all the replies! With this kind of community I feel that I am going to succeed learning Clojure!

🎉 9
practicalli-johnny17:09:17

@pmamatsis you may find this simple performance report on http-kit web server of interest http://http-kit.github.io/600k-concurrent-connection-http-kit.html

Michelle Lim14:09:46

👋 What are your favorite resources for learning core.async?

Michelle Lim22:09:38

Awesome, thank you

ramseyst18:09:36

Hi clojurists, I'm a total newbie. I'm trying to learn how to annotate function argument types using prismatic/schema. Is it possible to annotate that function argument x has one of two possible types, either type1 or type2 ?

ramseyst19:09:51

Aha, I think maybe I found it. Is it cond-pre ?

seancorfield20:09:15

@U01337FKP2B There's a #schema channel if you need it. I don't know how widespread Schema usage is these days (I think most folks switched to clojure.spec since it is built-in).

ramseyst20:09:58

Thank you! I will check out clojure.spec.

seancorfield20:09:05

There's a #clojure-spec channel if you get stuck, but there's quite a bit of documentation on http://clojure.org about it.

👍 3
Test This20:09:58

How to run tests? I am trying some Exercism exercises on Clojure. How do I run all the tests that come with the exercises in the clojure CLI tools repl. For example, today I worked through the isbn-verifierexercise. With the lein test command it was easy to run all tests. But I want to learn how to do things with Clojure CLI tools. The attached image shows some of the many things I tried. Nothing works. The folder setup is the standard setup that comes with the Exercism exercises (there is no deps.edn). Is that why I am having problems. Can someone please explain an easy way to run all tests within a file in test folder? Thank you. The image showing the directory structure is below. Thank you.

practicalli-johnny12:09:01

http://practicalli.github.io/clojure/testing/unit-testing/ has a simple guide to writing unit tests using Clojure CLI. With exercism projects you can add a deps.edn file to the root of a project after its created by the exercism command. This just needs the src and test paths and a test runner alias. As others suggested, you can also use a user wide configuration, saved in -/clojure/deps.edn which applies to all Clojure projects you run with the Clojure CLI tool (clj, clojure) Both Sean and I have examples of the user wide deps.edn configuration with lots of examples https://github.com/practicalli/clojure-deps-edn

practicalli-johnny12:09:06

The congnitect labs test runner is a nice simple test runner to start with. I do recommend looking at Kaocha once you start building bigger projects.

Test This23:09:34

@U05254DQM, Thank you so much for this. I was looking for a better repl than the standard one. I believe your deps.edn has that. Need to copy from there into Sean's that I downloaded 🙂. Will look into Kaocha too. Never heard of that before.

practicalli-johnny10:09:06

@curiouslearn I will be adding namespaces to the alias keys in the next release of the deps.edn config and making a few changes for the next Clojure CLI release https://github.com/practicalli/clojure-deps-edn/tree/qualified-alias-keywords-and-new-flags For a command line REPL, I do like using rebel readline. I mostly use a REPL through my editor, evaluating code from source code files rather than typing in the REPL.

seancorfield20:09:21

@curiouslearn Take a look at my .clojure/deps.edn file here https://github.com/seancorfield/dot-clojure -- it has aliases for lots of useful stuff, including running tests.

Test This20:09:48

Thank you @seancorfield. I will look into that.

seancorfield20:09:19

With those aliases in place, it's as easy as clojure -A:test:runner to run all the tests in a project (assuming they are named correctly).

seancorfield20:09:02

By "named correctly" I mean, if you have src/foo/bar.clj you should have test/foo/bar_test.clj for the tests -- so that's the foo.bar source namespace and the foo.bar-test test namespace.

Test This20:09:47

Thank you. That worked. I don't understand that file at all at this moment. Will have to read and try to understand it better. But it is great that it works for now. It appears that it pulls a few libraries to be able to run the tests.

seancorfield20:09:44

Yup. Cognitect (the folks behind Clojure) wrote a simple test runner that works with clojure.test and the Clojure CLI/`deps.edn`.

seancorfield20:09:02

(that's one of the libs that would get pulled in the first time you run tests)

seancorfield20:09:49

It's what we use at work for running all our tests -- and we have a lot:

Clojure tests 359 files 22680 total loc,
    4 specs, 1 function specs.

Test This20:09:35

Thank you very much. Now, while I will use this from now on to run the tests, for the sake of understanding, can you or someone please clarify why I cannot even load the test file in the repl. I went in to the test folder, started a repl and entered the following commands. But I cannot even load the file. Why is that? ❯ ls isbn_verifier_test.clj clojure/isbn-verifier/test ❯ clj Clojure 1.10.1 user=> (load "isbn_verifier_test.clj") Execution error (FileNotFoundException) at user/eval1 (REPL:1). Could not locate isbn_verifier_test.clj__init.class, isbn_verifier_test.clj.clj or isbn_verifier_test.clj.cljc on classpath. Please check that namespaces with dashes use underscores in the Clojure file name. user=> (load "isbn_verifier_test") Execution error (FileNotFoundException) at user/eval3 (REPL:1). Could not locate isbn_verifier_test__init.class, isbn_verifier_test.clj or isbn_verifier_test.cljc on classpath. Please check that namespaces with dashes use underscores in the Clojure file name. user=>

ghadi20:09:51

you're going to want to ignore load as a beginner, and focus on require -ing namespaces not loading files.

ghadi20:09:06

(require 'isbn-verifier-test)

Test This21:09:28

Thanks, @ghadi. But that does not work either. I tried it both from the root directory and from within the test folder. clojure/isbn-verifier/test ❯ clj Clojure 1.10.1 user=> (require 'isbn-verifier-test) Execution error (FileNotFoundException) at user/eval1 (REPL:1). Could not locate isbn_verifier_test__init.class, isbn_verifier_test.clj or isbn_verifier_test.cljc on classpath. Please check that namespaces with dashes use underscores in the Clojure file name. user=> clojure/isbn-verifier/test took 11s ❯ cd .. Exercism/clojure/isbn-verifier via :coffee: v14.0.1 ❯ clj Clojure 1.10.1 user=> (require 'isbn-verifier-test) Execution error (FileNotFoundException) at user/eval1 (REPL:1). Could not locate isbn_verifier_test__init.class, isbn_verifier_test.clj or isbn_verifier_test.cljc on classpath. Please check that namespaces with dashes use underscores in the Clojure file name. user=>

ghadi21:09:26

ok: so from the root of your project what do you see? ls -R

Test This21:09:54

I see the following. Please ignore the pom file since I was trying to play with the uberjar also.

Test This21:09:00

Isbn.jar README.md deps.edn pom.xml src/ target/ test/ ./src: isbn_verifier.clj ./target: classes/ stale/ ./target/classes: META-INF/ ./target/classes/META-INF: maven/ ./target/classes/META-INF/maven: isbn-verifier/ ./target/classes/META-INF/maven/isbn-verifier: isbn-verifier/ ./target/classes/META-INF/maven/isbn-verifier/isbn-verifier: pom.properties ./target/stale: leiningen.core.classpath.extract-native-dependencies ./test: isbn_verifier_test.clj

ghadi21:09:06

and what's in your deps.edn ?

ghadi21:09:14

specifically :paths

ghadi21:09:49

that determines which directories are available from within the clojure/java environment. You'll want ["src" "test"] at least

ghadi21:09:26

when loading code, both Clojure and Java look for code resources within the "classpath", which is a set of roots of trees

ghadi21:09:57

the trees can be folders (as you have above), or jar files (whose contents are a tree)

Test This21:09:31

I did not have test in my :paths. Now it works. Thank you! That is very helpful.

seancorfield21:09:19

@curiouslearn Normally you'd have a :test alias in your deps.edn that contains :extra-paths ["test"] -- you don't normally want "test" in your :paths

seancorfield21:09:17

It's easier for us to read code/output if you use triple backtick around it

like this
block of 
text

seancorfield21:09:47

I don't know how you're pasting in text and getting it all highlighted separately 😞

seancorfield21:09:25

Since you're not using lein, you can delete the target folder BTW.

Test This21:09:43

Thank you, Thank you @seancorfield. Really appreciate the help.

Test This21:09:06

Regarding the code, I was copying-pasting it, then selecting it and choosing the code button in the editor. But that does obviously did not work; it does in some places such as Stackoverflow; but not in Slack I suppose. Thanks for the triple backticks tip.

mathpunk22:09:23

I have a short problem, and a longer story (that interrogates whether I should solve the short problem or do something different). The problem: Given data like this,

[{::specs/message "Scenario 1" ::specs/level 0}
                      {::specs/message "Given" ::specs/level 1}
                      {::specs/message "When A" ::specs/level 2}
                      {::specs/message "it 1" ::specs/level 3 ::specs/type :assertion}
                      {::specs/message "it 2" ::specs/level 3 ::specs/type :assertion}
                      {::specs/message "When B" ::specs/level 2}
                      {::specs/message "it 3" ::specs/level 3 ::specs/type :assertion}
                      {::specs/message "Scenario 2" ::specs/level 0}
                      {::specs/message "it 4" ::specs/level 1 ::specs/type :assertion}]
produce output like this
[["Scenario 1" "Given" "When A" "it 1"]
                      ["Scenario 1" "Given" "When A" "it 2"]
                      ["Scenario 1" "Given" "When B" "it 3"]
                      ["Scenario 1" "it 3"]]
Long story in the thread...

mathpunk22:09:08

All I'm actually trying to do is take a bunch of scripts that are written in Typescript-flavored Jasmine, and extract only the plain language data, which in Jasmine, is present in describe and it blocks

mathpunk22:09:31

It sounded like I might be overcomplicating things if I tried set up a ClojureScript project, compile the typescript, read the javascript, and use Jasmine's various "getName" functions -- also we sometimes wrap our Jasmine scripts in classes

mathpunk22:09:21

So instead I wrote a function that removes all the code, and preserves only the messages, whether they're it or describe messages, and the level of indentation

mathpunk22:09:44

"Surely it will be straightforward to turn this information into the CSV-ready format that the product team seems more familiar with"

mathpunk22:09:56

reality: 😱

mathpunk22:09:58

I feel like trees are such a familiar structure that maybe, just maybe, if I posted the given and the desired result maybe someone would recognize it as a well-known problem

seancorfield22:09:49

I would construct a hash map from level to message, assoc'ing each entry as it is processed, and when an assertion is seen, reduce over a range to the level of the assertion, pulling items out of the hash map in order, into a vector that is conj'd onto the overall result.

seancorfield22:09:44

So a loop over the input data, with a reduce to build each vector.

seancorfield22:09:52

Does that get you started?

seancorfield22:09:08

I can probably gin up the actual code pretty quickly...

mathpunk22:09:46

if you did, I would promise to study it very hard and become a better person by doing so 🙏:skin-tone-2:

mathpunk22:09:28

I've been trying to write small functions that create intermediate data structures

mathpunk22:09:43

and I think if I squint I can see that they are attempts to do what you describe

mathpunk22:09:55

mm, so you would have a hash-map, and it is being assoc'd as we move along

jsn22:09:11

why a map though, a vector should do

mathpunk22:09:20

oh and assertions don't get assoc'd, instead the reduce happens

seancorfield22:09:57

(loop [input input lookup {} output []]
  (if (seq input)
    (let [message (first input)
          lookup' (assoc lookup (::specs/level message) (::specs/message message))]
      (recur (rest input)
             lookup'
             (if (= :assertion (::specs/type message))
               (conj output
                     (reduce (fn [v n] (conj v (lookup' n)))
                             []
                             (range (inc (::specs/level message)))))
               output)))
    output))
(assuming input is your sequence of maps input structure)

seancorfield22:09:19

tap> [["Scenario 1" "Given" "When A" "it 1"]
      ["Scenario 1" "Given" "When A" "it 2"]
      ["Scenario 1" "Given" "When B" "it 3"]
      ["Scenario 2" "it 4"]]

mathpunk22:09:40

you and your tap magic! still haven't brought that into my tool box 😆

seancorfield22:09:12

It's just the output in Reveal, since I use Chlorine and a socket REPL, and every eval goes into tap>

mathpunk22:09:29

I gotta look into Reveal

mathpunk22:09:33

Thank you for your help!

seancorfield22:09:53

#reveal is awesome 🙂

seancorfield22:09:12

I'm using it instead of REBL at the moment.

seancorfield22:09:00

(but, yeah, I use tap> extensively while I'm developing/debugging -- Reveal just happens to make that super easy)

Nazar Trut22:09:17

(defn loop-over-sets
  [expr kb]

    (dotimes [x (count kb)]
      (println (nth kb x))
      (if (= 'if (first (nth kb x)))
        (if (= expr (nth (nth kb x) 1))
           (nth (nth kb x) 2)
          )
        )
      )
  )
How come this returns a nil when

Nazar Trut22:09:20

(nth (nth kb x) 2)

Nazar Trut22:09:30

is suppose to return a sequence

ghadi22:09:00

check out the doc of dotimes by running (doc dotimes)

Nazar Trut22:09:13

dotimes doesnt return anything im assuming now

ghadi22:09:34

actually, yeah the doc isn't helpful.

Nazar Trut22:09:54

What im trying to do is loop through a sequence and return a sequence when i need it too?

ghadi22:09:55

"presumably for side-effects" is read as "doesn't return anything"

Nazar Trut22:09:02

what loop do i use for my problem?

ghadi22:09:04

what is the input intended to be, as well as the output? loop-over-sets doesn't describe that, it describes mechanism

Nazar Trut22:09:32

So this is suppose to be modus ponens, So my "kb" for example would be something like ((if a b) (if c b)) and my expr is 'a. So i would search my sequences for a 'if a' and if it exists in my sequence i would then return the b.

Nazar Trut22:09:29

I want my output to be 'b

seancorfield22:09:40

That sounds like filter -- you want any results that match your input expression?

Nazar Trut22:09:11

Ima look into filer

João Galrito22:09:47

(when-let [pred (first (filter #(and (= (first %) 'if) (= (second %) expr) kb))]
  (nth pred 2))

seancorfield22:09:50

(nm, @joao.galrito’s is closer to what you're trying to do -- I misread your problem statement)

João Galrito22:09:55

something like that

Nazar Trut22:09:39

I think there is a ) missing

Nazar Trut22:09:14

I tried running that code and it gives me dont know how to create ISEQ error

João Galrito22:09:22

I don't see it but it might

Nazar Trut22:09:42

unless i didnt place the ) at the corerct spot