

Erlang wasn’t the first implementation of CSP.
Erlang wasn’t the first implementation of CSP.
Clojure has it’s own set of idioms; it comes with some small surprises for old lisp hands. There are some things it’s really brought into the mainstream: performant persistent data structures in particular.
As well as excellent tooling and pedagogy, the principle attraction of Racket is the macro system. There’s a great book about this (this is true of just about all aspects of Racket). Racket’s focus is on building a tower of languages via macro extension. Metaprogramming is thematically FP-adjacent but neither sufficient or necessary; but if you’re looking for a fun learning experience it’s really worth a look.
In terms of employment opportunities - I know of several Clojure shops (on the JVM it has the bonus of being able to take advantage of the hole ecosystem), but I’m not aware of anywhere that’s using Racket outside of the academic sphere.
Another great avenue into this world is Racket. The tooling is fantastic and the documentation culture is first-class.
I’ve a couple of GP friend who used to describe “Dr Google” as their online colleague.
The point being, they were somewhat trained in interpreting risk as opposed to the stereotypical googler-of-symptoms. Once upon a time search engines were quite useful.
I’d go with Erlang over elixir, but it sounds like you already have an interest in gleam.
FWIW: just pick one and get started. There are some major axes to consider: pure versus impure, lazy versus strict, static versus dynamic typing, but to kick off if you’ve done no FP before it’s probably better to just go for it.
There are some really intriguing “next steps”: SICP, the ML module system, the Haskell ecosystem, the OTP approach to state, but to begin with it’s just worth getting used to some basics.
I kind of expected a lot of this; I remember the sendmail 4 book from back in the day when O’Reilly had that, DNS and BIND, and Perl as the entirety of its corpus.
I’m primarily transfixed, not by the example in your comment, but that you don’t voice the “th” in “with”.
And as for your specific question: typechecked code doesn’t get to production with a type error; it won’t compile. There’s a common phrase, “left-shifting errors”. It means catching bugs as early in the development cycle as possible. In terms of things like developer time (and patience), it’s far more cost-effective to do so.
I worked on OpenStack back in the day: millions of lines of untyped Python.
Let’s say you’ve got an X509 certificate. You know you can probably pull the subject out of it - how? Were I using Java (for instance), the types would guide my IDE and make the whole thing discoverable. The prevalent wisdom at the time was that the repl was your friend. “Simply” instantiate an object in the repl then poke at it a bit.
And it’s not just that kind of usability barrier. “Where is this used?” is a fantastic IDE tool for rapid code comprehension. It’s essentially impossible to answer for a large Python codebase.
Don’t get me wrong: python is still a great go-to tool for glue and handy cli tools. For large software projects, the absence of type enforcement is a major impediment to navigation, comprehension and speed of iteration.
You’ve linked into it, but I was just going to point at the Git book: https://git-scm.com/book/en/v2
It’s an afternoon’s reading; it does an excellent job of giving you the right mental model - and a crib aheet of commands to navigate it.
“Maybe our friend doesn’t like monads.”
I’m coming around to it.
That’s a cracking article.
My own use of jvm errors tends to follow the same kinds of patterns: I think the major fault with that model is having RuntimeException as a subclass of Exception, because it’s really intended for abandonment-style errors. (The problem is that lots of people use it instead as an exception system in order to cut down on boilerplate.)
I find it eye-opening that the author prefers callsite annotation with try
(although I’m not going to argue with their experience at the time). I can see this being either “no big deal” or even “a good thing” to Rust users in particular - mutability and borrowing annotations at both callsite and definition aren’t required to make the language work afaict (your ide will instantly carp if you miss 'em out) but the increased programmer visibility is typically seen as a good thing. (Perhaps this is down to people largely reviewing PRs in a browser, I dunno.) Certainly there’s tons of good food for thought there.
I’m not sure why it’s “obviously” good to move from one mechanism to two: as a user I now have to categorise every path to work out which is appropriate.
What I said was less about adding to a function signature than it was about adding to a facade - that is, a system boundary, although the implementation may be the same depending on language. People typically use exceptions pretty badly - a function signature with a baggage-train of internal exceptions that might be thrown by implementation guts is another antipattern that gives the approach a bad rep. Errors have types too (or they should have), and the typical exception constructor has a wrapper capability for good reason.
That’s fine, and for that there are sum types. My own opinion differs - it’s a question of taste. Being able to bundle the handling of exceptional situations aside from the straight-line logic (or use RAIi-style cleanup) is notationally convenient.
Yes, you can do the same with monads; use the tools available to you.
Checked exceptions are powerful but misunderstood. Exception types are a useful part of the facade to a module - they express to a caller how it can go wrong even if used correctly.
Runtime exceptions are typically there to express contract-breaking by callers; although as an alternative return mechanism I’ve seen them used to simplify the inner workings of some frameworks.
I think they get a bad rep because there aren’t a ton of good examples of how to use them - even the java classpath had some egregious misuse initially that helped turn people off the key ideas.
The other thing to watch out for is if you’re splitting state between volumes, but i think you’ve already ruled that out.
I’d be cautious about the “kill -9” reasoning. It isn’t necessarily equivalent to yanking power.
Contents of application memory lost, yes. Contents of unflushed OS buffers, no. Your db will be fsyncing (or moral equivalent thereof) if it’s worth the name.
This is an aside; backing up from a volume snapshot is half a reasonable idea. (The other half is ensuring that you can restore from the backup, regularly, automatically, and the third half is ensuring that your automated validation can be relied on.)
That depends entirely on the ability to execute change. CTO is the role that should be driving this.
The issue here is that the author of that post, and potentially the fictional author of the thing being lampooned, are not drawing a distinction between a tutorial (or an explanation) and a how-to.
https://diataxis.fr/
Either you want to get a task done, or you want to spend a lot longer learning how to work that out for yourself.
(Many tutorials will include small set of how-to-like instructions because emulating the actions of a master will improve one’s vocabulary of what can be done as well as how it is achieved.)