what is a simple symbol actually?
(defn simple-symbol?
"Return true if x is a symbol without a namespace"
{:added "1.9"}
[x] (and (symbol? x) (nil? (namespace x))))
seems to be a symbol whose namespace is nil
Didn't I read somewhere that the clojure reader is side-effect free? or am I remembering wrong?
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
> The data reader function is invoked on the form AFTER it has been read as a normal Clojure data structure by the reader.
perhaps you are thinking of there being no user-definable reader macros?
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
why not to call side effect function directly, without wrapping in let
? could you give an example
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/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
You are right. For whatever reason I thought do
only did side effects while not returning anything
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.
Another line of thinking: reduce over your list of filters. Relevant if you need to control how filters are applied.
[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?
Yes, it is possible, but via apply. (apply every-pred [fn-A fn-B fn-C])
Great, Thank you.
https://clojure.org/reference/transducers#_defining_transformations_with_transducers have a look at transducers
(sequence
(comp (filter fn-A)
(filter fn-B))
collection)
Thank you delaguardo, I will try this tomorrow morning.
Why not just (filter (every-pred fn-A fn-B fn-C) coll)
?
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?
@wls What do you use for websockets? Which routing library and server are you using? Thank you.
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
@curiouslearn, I'm using aleph.http/websocket-connection ... I had to do a little fiddling, though.
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/
@jr0cket, 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.
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.
there are also a couple of curses online. can’t recommend enough: https://www.learnreagent.com https://www.learnreframe.com https://www.learnreitit.com
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.
Building web apps in Clojure is what I do for a living @pmamatsis
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
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.
@manutter51 Really??? Wow! That's great! My end goal is to use Clojure for web applications! Meaning that there are web frameworks for Clojure?
oh yes....!
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
also the syntax of working with atoms already force you to treat it differently (with deref/@)
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.
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)
I haven't looked into the web side of clojure/clojurescript yet but I'm looking forward to it
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.
@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.
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.
@manutter51 you mean container based approach, right?
👋 What are your favorite resources for learning core.async?
Yeah. It’s not something I’ve ever needed to work with, but it’s out there.
http://Heroku.com supports Clojure for deploying web apps over AWS, for example.
🤦 how could I forget about every-pred
? too much transducers happen in my code recently(
@manutter51 and @wls really appreciate your replies. I will continue my journey into Clojure.
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&t=4s&ab_channel=Metosin
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..
Clojure is an excellent language for web development! and it can be used both in the backend and in the frontend via Clojurescript :thumbsup:
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:
@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/
@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.
Wow!!! Really appreciate all the replies! With this kind of community I feel that I am going to succeed learning Clojure!
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/
@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
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
?
https://purelyfunctional.tv/?s=core.async https://www.braveclojure.com/core-async/
Aha, I think maybe I found it. Is it cond-pre
?
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-verifier
exercise. 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.
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
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.
@jr0cket, 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.
@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.
@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.
Thank you @seancorfield. I will look into that.
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).
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.
@ramseyst 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).
Thank you! I will check out clojure.spec
.
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.
There's a #clojure-spec channel if you get stuck, but there's quite a bit of documentation on http://clojure.org about it.
Yup. Cognitect (the folks behind Clojure) wrote a simple test runner that works with clojure.test
and the Clojure CLI/`deps.edn`.
(that's one of the libs that would get pulled in the first time you run tests)
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.
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=>
you're going to want to ignore load
as a beginner, and focus on require
-ing namespaces not loading files.
(require 'isbn-verifier-test)
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=>
ok: so from the root of your project what do you see? ls -R
I see the following. Please ignore the pom file since I was trying to play with the uberjar also.
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
and what's in your deps.edn
?
specifically :paths
that determines which directories are available from within the clojure/java environment. You'll want ["src" "test"]
at least
when loading code, both Clojure and Java look for code resources within the "classpath", which is a set of roots of trees
the trees can be folders (as you have above), or jar files (whose contents are a tree)
I did not have test in my :paths
. Now it works. Thank you! That is very helpful.
@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
It's easier for us to read code/output if you use triple backtick around it
like this
block of
text
I don't know how you're pasting in text and getting it all highlighted separately 😞
Since you're not using lein
, you can delete the target
folder BTW.
Thank you, Thank you @seancorfield. Really appreciate the help.
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.
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...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
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
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
"Surely it will be straightforward to turn this information into the CSV-ready format that the product team seems more familiar with"
reality: 😱
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
(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(nth (nth kb x) 2)
is suppose to return a sequence
check out the doc of dotimes
by running (doc dotimes)
dotimes doesnt return anything im assuming now
actually, yeah the doc isn't helpful.
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.
What im trying to do is loop through a sequence and return a sequence when i need it too?
"presumably for side-effects" is read as "doesn't return anything"
what loop do i use for my problem?
So a loop
over the input data, with a reduce
to build each vector.
Does that get you started?
what is the input intended to be, as well as the output? loop-over-sets doesn't describe that, it describes mechanism
I can probably gin up the actual code pretty quickly...
if you did, I would promise to study it very hard and become a better person by doing so 🙏:skin-tone-2:
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.
I want my output to be 'b
I've been trying to write small functions that create intermediate data structures
and I think if I squint I can see that they are attempts to do what you describe
mm, so you would have a hash-map, and it is being assoc'd as we move along
why a map though, a vector should do
oh and assertions don't get assoc'd, instead the reduce happens
(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)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"]]
you and your tap magic! still haven't brought that into my tool box 😆
It's just the output in Reveal, since I use Chlorine and a socket REPL, and every eval goes into tap>
I gotta look into Reveal
Thank you for your help!
That sounds like filter
-- you want any results that match your input expression?
#reveal is awesome 🙂
yes
Ima look into filer
I'm using it instead of REBL at the moment.
(when-let [pred (first (filter #(and (= (first %) 'if) (= (second %) expr) kb))]
(nth pred 2))
(nm, @joao.galrito’s is closer to what you're trying to do -- I misread your problem statement)
something like that
(but, yeah, I use tap>
extensively while I'm developing/debugging -- Reveal just happens to make that super easy)
I think there is a ) missing
possibly
I tried running that code and it gives me dont know how to create ISEQ error
I don't see it but it might
unless i didnt place the ) at the corerct spot
Awesome, thank you
Got it to work, Thanks @joao.galrito and @seancorfield
👍