I’m probably in the second group (fp-beginner). I really only played around with CL, a colleague used it (that is a slight understatement, I think he would have controlled his household with CL but there’s just no interface for the dishes) and I really admired the productivity of his work. I just looked at CL, read a bit of Peter Seibel’s “practical common lisp” but never really implemented anything. A lack of spare time stood in the way of my ambitions then.
I think my struggles are not really different from most peoples who get in touch with fp: Thinking in recursive structures and not having digested a lot of the core functions and how they can be put to use. After all getting into fp feels a bit like someone is telling you to run the 100m and then suddenly switches of gravity. Some of your basic mechanisms just don’t work anymore
In the case of “brave and true” my mistake was probably wanting too much too early. There is an exercise to implement the “comp” function at some point. After fiddling around for sometime not really getting anywhere you look at (source comp) and wonder if that is what you should have come up with. Since you didn’t, you assume that you probably haven’t really understood anything of the pages you worked through. That’s no really a encouraging experience.
I need much more practice and my first-the-book-then-exercism approach was not the right one for me. For people with a bit more experience under their belt the book probably has the perfect tempo. It’s not cluttered, get’s to the point and shows you the elegance of the language.
Thank you all so much for your kind replies! I’ll have a look at the resources you provided.
This is such a great analogy! Yes, if someone is coming at FP from an OOP language and they find that there’s no traditional variables, no assignment, no encapsulation, no traditional loops (because there are no assignments and no variables)… that pulls the rug out from pretty much anything that they would intuitively try to use to solve most problems. It can be really tough to make that transition.
I’ve been setting up Atom (with parinfer, lisp-paredit, proto-repl, linter-joker, rainbow-delimiters, atom-beautify) [”apm install ink” results in an error].
The linter is looking at each line of output in the repl — and complaining about the prompt, for example. I’ve disabled linter for now.
Installing libraries — the only instructions I’ve found so far say to put the library as a dependency in the project’s … file (and Leiningen will go and get it).
That’s weird. I was expecting something like “lein get whatever”. What if I don’t have a project? If I’m just playing in the repl? I don’t want to create/edit some file (with weird syntax).
Everyone in Clojureland appears to assume MacOS users use HomeBrew. What about MacPorts?
Did I really just install go (the language) in order to install joker (a clojure interpreter/REPL) for the editor (atom) for a Lisp (clojure) [which has its own REPL]?
What is it with Lisp and modifier keys? I thought I was safe, by avoiding emacs, but now Atom wants me to do shift-alt-cmd-B to get the repl to evaluate the file I’m editing…
Guys! I grumble when I have to use even a single modifier (I was happy when I learnt “gg” instead of “1G” in vim). Now I have to send my hands on a yoga course (You try typing shift-alt-cmd-B one-handed!)
None of the Clojure books I’ve read (skimmed) so far [CftBaT, JoC, PC3e] seems very interested in reading/writing files.
So this is my only serious problem: the documentation. (doc spit) says (spit f x &options) and says to look elsewhere for the options. That place doesn’t actually say what the options are. Clojure-docs.org has some examples — but that’s not documentation (like a man page). Oracle java documentation has dozens of links about java.IO — but that doesn’t tell me what the Clojure options for spit and slurp are…
I can ask the web, but watching a YouTube video or someone’s blog is … unsatisfying.
—-
So, that’s what I’ve struggled with so far. But I still like Clojure!
Hum, I think you’re just facing the reality that not all these Atom packages are well maintained. I know proto-repl isn’t anymore, and maybe linter-joker similarly isn’t? You should try Chlorine instead of proto-repl for Atom.
The “weird” syntax is Clojure syntax , once you learn Clojure it shouldn’t be weird anymore.
If you don’t have a project, you add your dependencies on your global lein user profile instead located at ~/.lein/profiles.clj.
The doc isn’t great for lein to be honest. So this part is confusing. But you edit that file as such:
In the :plugins vector you add whatever global lein plugin you want to have. And in the : dependencies vector you add whatever library you want available globally.
Then anywhere you start a lein repl you’d have those dependencies available to you. And everywhere you run lein you’ll have the additional plugin features available to you.
If you use tools.deps instead of lein, aka, the clj command instead of the lein command. Then it is a bit different. You instead want to modify your ~/.clojure/deps.edn file. Where you’d add dependencies there instead:
{:deps
{clj-time {:mvn/version "0.14.2"}}}
So if you put the above in your user deps.edn whenever you run clj command the clj-time library will be available to you.
Not really. You don’t need to install Go for Joker. Joker is implemented in go, but doesn’t require Go to run.
So what you did is install Joker, a Clojure dialect, implemented in Go, but not Go itself.
There’s actually a superior linter called clj-kondo, it lints against many more cases, though it’s not a superset of joker, there are a few things joker catches that clj-kondo doesn’t. I use both together. And that one is implemented in Clojure itself.
Hum… I think this leaks from Emacs. I’ve noticed this myself as well. But it’s also that other editors already take over the most common keybindings, so it’s hard to find available ones that don’t conflict. In Atom you should be able to customize them all to your liking.
If you know Vim, you can try using Vim-iced for Clojure.
What do you mean? Like literally reading and writing to a file? That’s just one function: spit and slurp.
Oh ya, you make a great point about the doc for spit. There’s a few places like that where it is known that the doc is insufficient, or can be pretty compact and concise. I added a note to clojuredocs.org that specifies the valid options for spit. I think clojuredocs.org is the best place to find “additional” doc. It’s not only examples, if you scroll past the examples, there are notes, where people can provide additional doc or tips.
Someone probably should sign the CA, make a patch to improve the doc, and all that, but most people don’t have time for that, so they either do nothing, or they add some examples or notes to clojuredocs.org instead.
Thanks didibus! That’s all really clear and helpful.
Regarding the IO, I actually meant the whole thing: buffered/unbuffered, seeking, appending, streams, pipes, reading a single character from STDIN etc.
Joy of Closure appears to have one single call to (spit “file_name” something). And not a single slurp (?!)
That’s not a criticism. I’m just surprised. (I’m used to C and Perl. And no Java …)
I guess, what you have to know is that everything is an InputStream or an OutputStream, which is a binary stream of bits. And then you have Writers and Readers, which operate over an InputStream or an OutputStream and do decoding/encoding of the bits for you in various ways depending on which one you use.
But ya, beyond that, IO in Clojure is really Java’s IO mechanism. So it can even help to search about that. And most IO doesn’t have Clojure functions for it either, but it is expected you just use interop for it.
Seeking is moving to a position in the file; say you want to read byte number 300 in the file, in C you’d use fseek (3) to position a cursor into the file, and then read or write from there.
In Java-land, that functionality is provided by RandomAccessFile, so you should use that.
now… the overall theme of this entire topic is “what do beginners strugge with” and i have already pointed out the shortcomings of the clj-doc-approach in a previous post.
having said that, i think a more fundamental difficulty for beginners arises as a consequence of clojure’s quintessence, namely, being a HOSTED LISP.
what do i mean? well, first of all, it is always easier to learn / master something new, if you are already familiar with something akin to it. for example, if you do already speak
italian venturing into spanish will be much much easier for you than tackling japanese.
why? well because much of what you find in the spanish language is somewhat similar to what you already care and know about.
with japanese on the other hand everything!!! would be alien to you! instead of left-right-top-bottom people often write top-bottom-right-left, in addition to roman characters you get hiragana, katakana and last and most challenging chinese characters, instead of “normal” word order alla -bob likes lisp- you get -bob lisp likes-, no real grammatical number / gender…, counting… lets face it… counting is just a bloody mess, honorifics etc. etc.
…so… ultimately it really does come down to a different way of thinking… very much
how imperative programming and functional programming is much more about different ways of thinking, rather than any specific programming language.
so:
What’s in a name? That which we call a rose
By any other name would smell as sweet;
-----> no! global state and mutation reeks!?
anyway…point is… learning about any lisp will be a major challenge, because of the unfamiliar syntax and programming concepts.
but it gets even worse! not only is clojure a lisp but a lisp hosted on the jvm!
the difficulty here is that, whenever something is hosted on something else… or providing an abstraction over something else, i am convinced that this really requires you to know about the host also… the abstraction alone does really not suffice!
for example, i have always found that the biggest problem with ORM is that people are using it without a proper understanding of the basic underlying RDB concepts.
so what i am saying is this: if you wanna learn about clojure you’d probably do well to learn some other lisp and java beforehand. ( same goes for js and cljs )
now if you look at my youtube channel you will find a programming tutorial consisting of 200 ( or so ) episodes discussing first emacs lisp, then urging the viewer to check out
some java ( “effective java” etc. ) on her own… and ONLY THEN… ( having established those crucial foundations ) do i start discussing some basic clojure.
bottom line, getting to grips with clojure is super tough, but perhaps that’s also what’s making it fun… kinda
anyway… i am still struggling with clj myself,… but far from giving up!!! in fact i got myself a sweet deal on the living clojure book… which has been recommended by seancorfield,… should arrive any day now
final remark and coming back to spoken languages,… obviously… - really this goes without saying -… obviously one can never fully / really master any language… native speaker / programmer or not… what with the infinite and ever evolving universe of subtleties, connotations, dialects, idiolects, idioms etc. etc.
p.s. not everything in life needs to / should gravitate around efficiency, pragmatism, practicality and ( sadly looming all too large all too often ) expediency!!!
We’re losing about one language a week, and by some estimates, half of the world’s languages will be gone in the next hundred years.
It’s week 2 of my clojure journey, so I fall flat-faced into the ‘beginner’ category. I have no prior experience with LISPS, but have done some work on the JVM (Java & a bit of kotlin), and am marginally exposed to functional concepts (albeit via javascript).
So far the actual Clojure coding I’ve done has been limited to exercises (4clojure, koans, exercism) and replicating bits and pieces from books (Living Clojure; Clojure for the Brave & True).
The only real language-level frustration I’ve had so far is just the generic fact of not knowing enough, particularly about the stdlib, to get any momentum. But constantly having to stop to look things up is a given learning any new language or platform.
I think the ‘problem’ of lispy syntax is way overblown, at least for experienced programmers. Once you’ve been coding for a few years, you’re mostly thinking in something nearer to AST’s than the surface-level syntax anyway, and it seems like a non-issue to me to move to a different syntactical structure.
So my main actual frustrations so far have been:
re-arranging nested forms when I’ve got into a mess with one. This is totally self-inflicted. I ignored (good) advice not to start with paredit, and have more than once spent 10 minutes or so just trying to re-arrange something I’ve just stuffed up.
not knowing what tools to use, eg. lein with project.clj vs clj with deps.edn. Options with the basics are not useful to a beginner
not really understanding the relationship between the REPL and the code I’ve connected to it (in Emacs/Cider). Several times I’ve had errors I couldn’t fix, only to find the ‘same’ code worked in my next session. I assume I must have evaluated different groups of forms without quite following the implications
compiler errors are often obtuse and hard for me to make use of. They’d be impossible if I had zero Java/JVM experience
official Clojure API documentation tends to be terse and assumes a high level of familiarity with Clojure terminology (this is how it seems to a beginner, anyway).
I notice I’m not listing much there about the language itself, which actually seems rather clear, at least at the toy/puzzle level I’ve been inhabiting so far.
I’ve a feeling I’m going to hit a wall when I get to building real applications, lacking mental templates for the best way to arrange a bunch of functions so they don’t just form higher-level spaghetti architecture. I’ve asked around in a couple of places for excellent codebases (particularly whole apps) to use as exemplars, but haven’t come up with much. I’m wondering if there just might not be many high quality Clojure open source apps around. Still looking though.
I’ve a feeling I’m going to hit a wall when I get to building real applications, lacking mental templates for the best way to arrange a bunch of functions so they don’t just form higher-level spaghetti architecture. I’ve asked around in a couple of places for excellent codebases (particularly whole apps) to use as exemplars, but haven’t come up with much. I’m wondering if there just might not be many high quality Clojure open source apps around. Still looking though.
mtgred/netrunner is a good example of what a mature app looks like, although it is huge and probably pretty hard to get into. seancorfield/usermanager-example seems to have the organization of a large project, but broken down into a manageable size for learning. These are both web apps, but it’s a pretty common pattern to have separate layers for storage/DB, presentation, and routing/startup.
Completely correct on the first point. I’m a beginner and I’ve no clue how to set up a proper basic clojure REPL environment. In Python, it takes one second to open the REPL. And my python REPL stays open for days until it crashes. I read LISP REPL can run forever but setting them up is a mystery
For the most part, folks just run lein repl (or clj if they’re using the new CLI/deps.edn but see the caveat below).
If you let Leiningen start a REPL, you can type into it – just like the Python “REPL” – and you can connect all Clojure-aware editors to it (lein repl tells you the port number its “nREPL Server” is running on and you can use localhost and that port number when connecting your editor to it. At that point, you can eval from your editor into the same REPL that you can also type directly into.
Caveat for CLI/deps.edn: unlike lein repl, this just starts a simple interactive REPL that you can type into. There are various ways to start other REPLs – see https://github.com/seancorfield/dot-clojure/blob/master/deps.edn#L59 for examples. I personally like to start a Socket REPL (clj -A:socket) since I use Atom/Chlorine which doesn’t need nREPL.
I read the very well written guide. It is very clear.
I’ll need to install correctly homebrew, then a full-fledged flavor of Java, CLJ (or Leiningen) and set the right path and environment variables. I’ll give it a try. I never installed Java and that will be the first big challenge as homebrew seems to have an installer.