Here is the Dan Grossman’s Caml tutorial (refresher) for Ocaml. The cool thing about it is that it shows how little we all need.

https://homes.cs.washington.edu/~djg/teachingMaterials/gpl/lectures/camlTutorial.pdf

He is actually a very cool guy, who teaches the principles (and precise semantics) of programming using the classic languages – SML and Ocaml, which were carefully designed by talented math majors to build theorem provers and proof assistants.

These languages (and Erlang) ought to be “all you need”, but the world is what it is (Pootin, Trump and what not) so we have Java or C++ or, if unlucky – PHP or Javascript.

Now there is something profound to realize: “all you need” from a language is “just” functions (lexical closures) and algebraic data types. This has not been “invented”, this has been discovered (look up what the Curry-Howard Isomorphism is about).

Another discovery, was that the data-constructors could be used as “type tags”, and any “algebraic structure” could be pattern-matched against them.

Structural Pattern-matching is a very universal notion, so universal that biological enzymes are using it. Well, technically, ours is a proper generalization of biological.

There are very important and overlooked subtleties too. We need an Environment, which corresponds to a set (the notion of an order is irrelevant) of all previous results – \(\Gamma\) – or what is already known in logic.

Every evaluation (or simplification of a proof or of logical terms) is done withing some Environment and, in addition, a local context.

What is a context? It is a chain of nested frames of the environment, so shadowing of the symbols (or overloading of the concepts) can occur.

You have no idea how deep it goes and what has been [properly] captured as the result of activities in the golden age of Functional Lineages research (which started with ISWIM culminated in Haskell 2010).

All you really need are bindings (between symbols and values) in the Environment, and another set of mappings between values (referenced by symbols) and its types. This is an “additional layer” of the environment and this fact is nicely captured by the “above” notation Haskell uses for writing types of functions.

There is another fundamental notion – of partitioning, and even more fundamental – of nesting.

Nesting gives you scopes and modules, which are the most important aspects of code organization (structuring), and a proper generalization of nested function calls gives us “Currying”.

Curried functions is the necessary basis for partial applications (they have to be proper lexical closures too), and partial application allows us to extend the language with out own “control-flow abstractions”.

Algebraic types (and GADTs) allow us to extend the language with new kinds of the data [items] in a very systematic, mathematically general way.

On a higher level, everything has to be “layers upon layers of DSLs”, each of which, ideally, shall be monoidal (this is what the MATLAB/Octave language evolved into). There is also that “Architecture of Complexity” paper by Herbert A. Simon.

Notice, noting described so far is redundant or arbitrary. Every “feature” is necessary, is orthogonal to and complements other features, and, it turns out, will be sufficient for everything commutable.

Well, the Simple Typed Lambda Calculus is sufficient, we are just discussing what has been discovered to augment it properly and to extend it with better, advanced types (and type-classes).

So, this is the universal basis. All the great (really) classic languages – Standard ML, Miranda, Ocaml, Haskell, Scala 3, F# – have been built upon this universal basis discovered intuitively by mathematicians, logicians and “applied mathematicians” who program the first computers.

There is, however, a problem. A lot of them. Lots and lots of problems.

These classic languages has been carefully designed to enable a fast prototyping (among other thins). It is actually very straightforward – one models with well-understood mathematical concepts, and then just tries it in this or that classic language.

The basis reflects the basis of mathematics itself. It can be even traced back to the discovery of so-called Curry-Howard isomorphism (which shows that the Elephant is actually out there and it is one and the same).

By the way, before talking about the problems… A language for so called “smart contracts” (which no one actually needs or wants, except scammers) shall be built on this universal base. Even KRC not even full Miranda was enough for this use case.

It has to be extended with two major innovations: the pattern-matching on receive, from Erlang, so that pure structured values would be introduced to the scope (Erlang did this just right) without breaking referential transparency (structured value is a result of evasion of a corresponding clause of a pattern-matching expression – just like a “partial” function, defined using clauses, which reflects partitions in the domain).

One could also lift both send and receive primitives into an IO Monad, which is also the most natural thing to do, but even this is not necessary for a smart contract, which does not have much of error handling logic (they assume send and receive are atomic and always succeeds).

Either Miranda’s esoteric approach (compiling into the SKI combinators) or what Haskell does (the G-machine) is absolutely secure, because it evaluates stateless “declarative” expressions, as one would do with a pen and paper. And no, you don’t have to have these boxed 256bit values. The early satellites flew on 16bits.

So, the problems…

Today’s de-facto fast (and very productive) prototyping languages of choice is Python. Python is eating the world (thank god the Javascript madness is fading away).

There are a few good things about Python. Its truly dynamic nature – whatever hangs out from an object (literally) defines its duck-type, so to speak, and the ability to decorate any value and a “function” with actual types, which can be checked for correctness using specialized packages.

This unique kind of typing is arguably the best for prototyping. One starts dynamic and then gradually adds some sanity checks.

Another seemingly good thing about Python is that there is a library (or two!) for literally anything on Guthub (PyPI). The problem is that most of these libraries are absolute low-effort crap, ridden with useless, redundant abstractions, fucking useless async and what not – the junk food of programming.

The answer to this is very careful nesting at the level of modules, so one wraps crappy interfaces inside wrappers which exports a good interfaces. This approach also keeps the dependency hell manageable, but requires a lot of careful work. This is where the real craftsmanship begins (partitioning of the code with “cell membranes”).

The smart mathematical majors of the past have created amazingly powerful module systems (SML in particular) to solve in general exactly this kind of problems, but no one cares or even thinks about such things seriously.

The problem with all the classic languages is lack of a library for literally anything somewhere on Github. This is NOT because these languages are worse than Python. On the contrary, they are superior in many aspects, but to understand and appreciate this requires a proper serious education.

Some cool guys have “ported” some good Python code to modern Scala (this fact proves that Scala 3 is almost as expressive, being properly statically typed), but this is the rarest case of a true intelligence.

Another problem is that neither proper sum-types nor product types (so called record types) could be properly (yes, yes) defined in Python – one has to use classes or data-classes, which introduce redundancy and complexity. Having “just values” (not objects) is enough.

Not just redundancy and added complexity, but it can be shown that a set of values with corresponding set of operations (a public interface exported by a module) is isomorphic to class-based definitions, provided the implicit parameter “self” is just, well, a parameter. But having a “pure values” (without a hidden state) makes everything reverentially transparent, just like math.

There is a famous (among learned scholars) presentation by Scott Wlaschin about “domain modeling”:

https://www.youtube.com/watch?v=MlPQ0FsPxPY

The absolutely amazing moment, at lest to some, is that “Where is the code?” remark and the subsequent realization that “everything typechecks”.

This, however, has nothing to do with mr. Wlaschin, however cool and clever his presentation is, but to the fact that the creators of ML (and Ocaml), of which F# is a dialect, have done the Algebraic types just right, and everyone else did it plain wrong.

Watch the video, maybe you will hit by some premature enlightenment.

One more time. There is the universal basis for programming, which is a smallest possible set of orthogonal (but complementing each other) extensions to the Simply Typed Lambda Calculus. It has been re-discovered by both “strict” and “lazy” traditions (while the “lazy” tradition has discovered even more universality).

Theoretically, the classic math-based languages of the ML family are simply superior to the current popular imperative crap, and as a consequence of being popular instead of good (yes, yes, Ayn Rand) we have this problem – lack of high-quality libraries for the mundane stuff. Ocaml is slowly accumulating some, thanks to Jane Street.

By the way, there is a complete fully functioning blockchain, which has been written in Ocaml by a very small team on almost ramens (just kidding). Its codebase is “agile”, much more clean and easier to understand and maintain – everything that has been promised by the best (applied mathematics) theoreticians can be actually seen within this project.

https://github.com/tezos/tezos-mirror

To summarize, the problems are not with the classic languages, they are almost perfect (really), the problem is “the coders”, who are ignorant, uneducated and have been raised on social media bullshit, like /g/ or modern HN, and now on the AI slop.

And yes, there are way better things than Python or Javascript (leave alone C++ or Java) out there (the X-Files music theme is playing in background).