This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-08-18
Channels
- # announcements (22)
- # asami (7)
- # babashka (43)
- # beginners (68)
- # biff (2)
- # calva (10)
- # clj-kondo (7)
- # cljdoc (29)
- # clojure (41)
- # clojure-austin (1)
- # clojure-brasil (2)
- # clojure-europe (25)
- # clojure-gamedev (3)
- # clojure-nl (2)
- # clojure-norway (9)
- # clojure-uk (31)
- # clojurescript (3)
- # community-development (7)
- # cursive (3)
- # data-science (4)
- # datomic (17)
- # emacs (30)
- # honeysql (10)
- # hyperfiddle (39)
- # introduce-yourself (1)
- # jobs-discuss (5)
- # kaocha (1)
- # lsp (11)
- # malli (12)
- # pathom (18)
- # pedestal (3)
- # proletarian (2)
- # quil (11)
- # rdf (46)
- # reitit (8)
- # releases (2)
- # shadow-cljs (34)
- # sql (3)
- # squint (10)
- # tools-deps (24)
- # xtdb (10)
Hello everyone - I am new to Clojure. So far clojure seems very interesting and much closer to my unix frankenstein one liners like cat file.txt | grep someregexp | awk '{print $1,$2}'...etc. etc..That get so much accomplished at work so quickly. I have a few questions: • I am having a lot of trouble getting an interactive REPL working. I am using a MacBook. I tried Calva and Lein repl. But they wont fire up the repl. So currently I am just scripting in a file and then pasting into the clj repl. I get this "Jack-in process exited. Status: 1" for calva and "Could not resolve dependencies" for lein repl • Can you do a thread last to a for loop. I want to take a list of strings and "pipe" to the for loop where I print out each string on a line. • I am not a big vscode user (I use vi!), Calva's getting started scripts says the following. There is no Alt key on a mac. ◦ ;; Start with loading this file. ◦ ;; Ctrl+Alt+C Enter • I do a lot of text manipulation, basic pandas data frame stuff, and building of command line tools. Should I use ClojureScript or Clojure? Thanks!
Hi! I totally agree about that feeling of using Clojure compared to composing unix command line tools. It’s pure joy and a sense of being productive.
• Not sure how Calva/the repl is failing you. But it sounds a bit like you don’t have the project structure that Leiningen needs. Maybe we can find some guide talking about setting up a minimum Leiningen project. Feel welcome to the #calva channel for help with getting started with it.
• You can create a function and give the arguments to for
. However, since you want to print the strings you are probably looking for https://clojuredocs.org/clojure.core/doseq (https://clojuredocs.org/clojure.core/for yields a lazy sequence). Depending on what you want to do, also check out run!, which just runs a function on the items of a collection e.g. (->> ["a" "b" "c"] (run! println))
.
• The Alt key is named Option on some computers. I’ve updated the getting started instructions about this now. If you run the getting started repl again and choose to download new files you should see it. Thanks for reporting! I’ve heard that vi people are happy with NeoVIM + #conjure.
• Sounds like you should consider #babashka or #nbb. Clojure is also fine, but it comes with a startup time that is not always acceptable for script tools. You could use #shadow-cljs to build yourself nodejs scripts, but it is not always the workflow to go for. Babashka has a lot of utilities to aid with shell scripting. I wrote a thing about converting a bash script to Babashka that highlights this a bit: https://blog.agical.se/en/posts/changing-my-mind--converting-a-script-from-bash-to-babashka/
Also, if you're used to vi/nvim check out vim-fireplace (this was my starting point a few years ago and I still use it happily: https://www.juxt.pro/blog/vim-1/) or Conjure: https://github.com/Olical/conjure
OK thanks for all the very helpful advice @U0ETXRFEW and @U018D6NKRA4 I really appreciate it. I have also read a little about babashka and will definitely try it out. What I would love to do is take my scripts and give them to coworkers to run as tools. I can do incredibly powerful things at work with unix and python but when a coworker tries to use my work its often a non starter. So something like shadow-cljs may do the trick. And I will also check out vim-fireplace. For context: Here is an example of what I am trying to duplicate in Clojure. The video shows a python based command line utility I created called Gather and then I filter the data with anything that works (sed, awk, grep, more scripts). A big win would be just the text processing and data science-ish number processing. A earth shattering win (for me) is if I could build Gather in clojure as well. Anyway thanks again! https://www.youtube.com/watch?v=-qMmF1vU6PI&t=2s
Warning this could be TMI...Please disregard if its annoying. If your interested in looking at the code for Gather to see if the ssh stuff works in clojure here it is: https://github.com/rantlabs/rant Script gather.py with main engine being on line 71 (about thirty lines of code). It just logs into many devices (routers, servers, firewalls, etc...) issues commands and dumps output. The other key is logging in and dumping commands needs to be concurrent. The more concurrency I can manage the better. Which at the moment is about 30 simultaneous threads. https://pypi.org/project/gogather/
> when a coworker tries to use my work its often a non starter Just to get a better understanding of the problem. What is it that makes this hard for coworkers ?
I’m quite unfamiliar with the problem domain, but generally it looks like Gather itself would be a good task for Clojure. If the startup time is important you can probably compile it to a binary the same way Babashka is compiled. (And depending on where the performance is needed it might be a good task for Babashka, in which case startup time is fast and nice.) I get the feeling that a lot of the problems you are solving with your scripts and command lines are pretty awk shaped, and then awk is unbeatable. 😃 But Clojure/Babashka can come pretty close, and things get so much more maintainable with Clojure is my experience. I guess the way forward is for you to quickly get where you can make a few experiments around the things you see as the biggest risks wouldn’t port well.
The main problem with distributing scripts piped to awk and sed and more unix and more scripts is that my coworkers are sometimes not that technically savvy or are using windows or dont have python installed or something. If I could give them a binary or a jar file they could use the code vs having me run the duct taped code and scripts. Also startup time is not an issue at all in my use cases. snip... I get the feeling that a lot of the problems you are solving with your scripts and command lines are pretty awk shaped, and then awk is unbeatable. 😃 But Clojure/Babashka can come pretty close, and things get so much more maintainable with Clojure is my experience. Exactly what I was thinking. Thanks again. I will try Babashka. In the process of trying out vim-fireplace.
I have a question about the first
function. the documentation says that it calls seq
on its argument. what is the consequence of calling seq
on a lazy sequence?
Otherwise stated, what is the best way to retrieve the 1st element of a lazy sequence, but return nil if the lazy sequence is empty, without accidentally forcing the generation of any element beyond the 1st?
thanks. I notice chunk
has no docstring.
i'm not 100% sure I understand.
If I call a function which returns a lazy sequence, but I don't access an element of it yet.
Do I know it has not yet generated anything?
Does that mean I just need to re-chuck
at ANY time before accessing some sequence element?
no you need to use re-chunk only in rare cases where you absolutely don't want to realize no more than requested elements from lazy sequence
so if I want to really take the elements one at a time, then I can re-chunk either at the creation site or at the call-site or anywhere in between.
the latter is better
I was under the impression that generating a lazy sequence might actually generate some of the elements. I'm happy to clear up my misconception. 🙂 Why is latter better? Does de-chunking force one to be computed?
depends on how you generate such lazy sequence
later is better because something in between might drop rechunking and at the call site more than requested elements will be realized
Hello guys, a beginner question about react wrappers in Clojure. I was a bit surprised to find so many of them. And making choices about which to learn and use turned out to be quite the study. Would people be willing to comment of Reagent, Re-frame, Helix and UIx? What are the strengths of each and which would be a solid platform for more complex web-applications?
This provides a helpful summary: https://www.youtube.com/watch?v=fT28NeZtaAg
Are you limiting your search to React wrappers?
btw, given the stipulation "more complex", I have cloned https://kennytilton.github.io/whoishiring/ using Reagent, and I had fun, but that is a simple app state-wise, and I sensed the wheels would come off on sth deeper. As for the others, if you are dead set on React, research how well re-frame is keeping up with modern React. Then ask if you are down with the Flux architecture of re-frame and, I just discovered, Uix. As for Helix, research what solution it has for app-wide state management (not just local hooks). When I went searching for a JS framework ages ago, I had a definite target app, and spent a few days implementing it in Dojo, Yui, one other I forget, and finally qooxdoo. That worked well, because they all sound great, but the coding led to surprises.
Ah perhaps I phrased that wrong. I'm in the process of selecting a frontend framework that could serve as a basis for commerce stores. probably the most complex elements of these websites would be product search and filtering as well as cart and checkout interactions with different providers. At the moment i'm trying to form an opinion of the current state of affairs to select candidates for trying things out. It's not deadset to be react based if other production ready options exist
Oh, what about mobile? Any plans for that down the road? If so, consider also Flutter via ClojureDart. I have never done ecommerce, but it looks like support for that is good: https://www.linkedin.com/pulse/why-flutter-future-cross-platform-e-commerce-app-development/ I suspect from what you say your state management needs are not too extreme, so re-frame, Helix, or Uix will do. re-frame sits atop Reagent and fixes its state glitches, as well as offering Flux. Again, I would look more for off-the-shelf ecommerce add-ons that may already be integrated with a CLJ React wrapper and go with that, only because to me that seems like the hard part.
Thank you very much for your suggestion. I'll be looking into that. When it comes to mobile the current approach would be to run a website with differing styles for mobile and desktop and minorly different functionality on mobile devices. Interactivity would be designed on mobile first and extended to desktops later. Standalone mobile applications are not being planned for this leg of the journey.
Oh, def consider Flutter. One code base, with easy identification, when necessary, of whether we are on Web, mobile, or desktop. I demo me handling a hover requirement on all three here, including the case of mobile where hover does not apply: https://youtu.be/OkotzUNKkUE Speaking of myriad wrappers, sorry, you still have a choice: cljd.flutter, re-dash (a re-frame workalike), and my lib, flutter/mx. I also have a web version, so I am impartial Flutter v Web. I just think Flutter in general is now a stronger platform than the Web or RN.
Hi! A newbie spec question, are there any differences with below two forms, or shall I just use normal and in below cases?
clojure.spec.alpha :as s
(s/def :param/myint (s/and int? #(< % 5000)))
(s/def :param/myint (and int? #(< % 5000)))
yes, there are differences and you want s/and
the and
version will evaluate - int?
is a function so logically true, same for the anonymous function so the latter is equivalent to (s/def :param/myint true)
which I'm sure is not what you intend. the s/and
will build a spec
oh i would have thought it would be equivalent to (s/def :param/myint #(< % 5000))
(ignoring the first value since it is truthy)
ah, right
I see.. that's why I played some values in repl and thought they're the same..int? is silently ignored but the #(< % 5000)
is doing its job in second case. Thanks for explaining guys!
But lambda doesn't have generator attached. So you want int? as the first predicate anyway, because it does have generator for integers. And that lambda will throw ex if any non-number is provided I think.
... so you should start with type-checking predicate.
Is there a reason this returns an object and not 3?
(some-> 3
(fn [a] a))
You are not actually calling a function, you are creating one though
user=> (macroexpand '(some-> 3 (fn [a] a)))
(let* [G__143 3] (if (clojure.core/nil? G__143) nil (clojure.core/-> G__143 (fn [a] a))))
user=>
user=> (macroexpand '(clojure.core/-> G__143 (fn [a] a)))
(fn* G__143 ([a] a))
user=>
If you wrap the function in another form you will call it like you expect
people often think of the arrow macros as "wraps things in parens" so (-> 1 F) is (F 1)
the but the arrow macros are "insert at a specific position in form, wrapping in parens if not already wrapped in parens"
I'm a bit confused. Isn't (fn [a] a)
just a drop in anonymous function for say (defn foo [a] a)
user=> (-> 3 (fn []))
Syntax error macroexpanding clojure.core/fn at (REPL:1:1).
3 - failed: vector? at: [:fn-tail :arity-1 :params] spec: :clojure.core.specs.alpha/param-list
3 - failed: (or (nil? %) (sequential? %)) at: [:fn-tail :arity-n] spec: :clojure.core.specs.alpha/params+body
user=>
Do Macros not resolve and then error out?
with some-> you don't get an error because it happens to replace the literal 3 with a symbol that is bound to 3 at runtime
but macros are expanded away as a sort of desugaring step before the rest of a form can be evaluated
so at macro expansion time for a form like (-> 3 (fn []))
its all just forms, (fn [])
is a list
the reason you get an error for the -> case and not the some-> case is the -> case expands to (fn 3 [])
which is not valid according to the syntax for fn, but the some-> case expands to something like (fn X [])
which is valid syntax for fn
I didn't know that was valid for fn
I'm essentially trying to replace this
(def x {:callback (fn []
(println "calling callback")
true)})
(if-let [callback (:callback x)]
(if (callback)
nil
(fn-to-run-if-no-callback))
(fn-to-run-if-no-callback))
Which feels very unclojure like. I thought some->
might be a good way to make this read better. We're just checking if a map has a function, calling it, and seeing i fi returned trueThat won't work because if the callback runs and returns nil, I need to run fn-to-run-if-no-callback
as well
Not sure how or would be used in this context. And if you mean evaluate the callback when building a map, this map is coming from a route handler on the frontend so the callback needs to be evaluated every time. I just made a simple example. I have to help someone move so I'll check back in here later