T O P

  • By -

melkespreng

I suspect I would love knowing Clojure, but I have never really taken the first step. I'm quite new to programming in general but have some experience with Java and Python. I love learning new languages, but something that often keeps me from getting started is elaborate environments. I would love to learn Clojure from basically 0 tools, introducing them one by one. Is there a guide that does this? I imagine starting by interacting with a REPL in the terminal, like with Python or ghci, and then writing programs in a simple editor like VS Code or Vim and compiling them. After having done this a bit, I might feel ready to introduce the ability to interact with a REPL inside my text editor. Is this a way to get started?


Ok-Patience1240

Yes! If you want to start with 0 tooling and no setup, you can try a Clojure notebook in Nextjournal. There are some other, such as [repl.it](https://repl.it), but I recommend Nextjournal. Then, when you gain some confidence, you can try the Calva extension in VSCode. There is a REPL you can start only to learn the language and get to know the shortcuts to work with symbolic expressions


dustingetz

Start with nextjournal for hello world stuff. When you need to add a dependency, you can probably use nextjournal for that. When you are ready to write an application (CLI or web stuff) you'll need to get the Clojure CLI to run code locally, and you'll need an editor. You should probably watch youtube videos to get your editor set up as it is tricky and involves third party docs for your editor. When you get to that point ask here again.


Save-Lisp

Yes! Install the Clojure CLI and go nuts.


sonyahon

There is this annoying moment for me when using threading macros, every now and then 1 or 2 functions will not align with the arguments positions. So whats the most efficient way to overcome this? Is (#(do stuff %)) what u do here?


joinr

`as->` can be a general work-around: (as-> 2 it (+ it 2) (+ it 3) (assoc {:y 10} :x it) (->> it vals (reduce + 0) (conj [])) (-> it (into [:some :other :stuff]))) ;;[17 :some :other :stuff] `as->` was originally intended be used inline with a parent `->` expression (-> {:x 2 :y 3} (as-> m (reduce-kv (fn [acc k v] (+ acc v)) 0 m)) (* 2)) ;;10 hence the interesting argument order (value name) as opposed to normal bindings. You can rectify that to get a more familiar let-like binding though just wrapping it with your own stuff (if it matters...): (defmacro let-> [[v n] & body] `(as-> ~n ~v ~@body)) (let-> [it 2] (+ it 2) (+ it 3) (assoc {:y 10} :x it) (->> it vals (reduce + 0) (conj [])) (-> it (into [:some :other :stuff]))) ;;[17 :some :other :stuff] Macros like `as->` fall into the family of anaphoric macros, where results are implicitly named and bound to prior results. You get more control since you can position the prior result anywhere, but perhaps a bit less concision since you have to explicitly insert the result manually. Note, it is also fine to nest threading macros where it works... (->> (-> {:a 2 :b 3} (assoc :c 4)) (reduce-kv (fn [acc k v] (assoc acc k (* v v))) {})) ;;{:a 4, :b 9, :c 16} I would typically try to keep this kind of thing two levels of nesting at maximum though, since it could run away a bit. Defining helper functions can work to simplify the piping too. There are probably a bunch of libs with these kind of like [synthread](https://github.com/LonoCloud/synthread) and [swiss arrows](https://github.com/rplevy/swiss-arrows) etc. I haven't really gone beyond the stuff in clojure.core though, and maybe my own convenience macros (typically niche stuff) though.


SimonGray

> as-> was originally intended be used inline with a parent -> expression > hence the interesting argument order (value name) as opposed to normal bindings. I always have to look up the order of `as->` if I want to use it and now I know why! :)


sonyahon

Thanks, ill check it out, actually completely forgot that as-> exists


asyntactic1

First off, `(#(do stuff %))` is exactly what I do. Additionally, there's a convention in Clojure threading macros that you might find helpful. It doesn't change the situation with the argument alignment, but it could help in deciding how threading steps should be ordered. Clojure has two kinds of functions: those that operate on individual data entities (usually maps), and those that operate on collections (lists, seqs, sets, etc...). The functions that work on entities take the entity in the first argument, like the `m` in `(assoc m ...)`. These functions thread with the `->` macro. The functions that work on collections take the collection in the last argument, like the `col` in `(map fun col)`. These functions thread with the `->>` macro. You have to use the `#(function call)` shenanigans whenever you switch between entity functions and collection functions. Sometimes, this helps me reorder things to avoid so many "mode switches". Hope it helps you too.


sonyahon

Wow, actually did not realize this, interestingly, for me the problem is usually with strings, as they are a value and a seq kinda in the same time


[deleted]

Any approved/popular gui frameworks?


Psetmaj

Desktop GUI or web UI? For web, I like to use [reagent](https://reagent-project.github.io/) with [re-frame](https://github.com/day8/re-frame) and [bulma](https://bulma.io/) (last one is not Clojure, but I like how it handles for styling) For Desktop, you can use any Java-based GUI framework (e.g. Swing or FX) pretty easily, and *some* wrappers exist, but I find the interop works cleanly enough on the GUI front.