There is only one true way (the proper way) to program. Just as there is only one “reality”, one “truth” (which correctly describes What Is) and The Right Way (of the Buddha, which means being firmly grounded in What Is).

Imagine, if you will, that you are writing a program for yourself which will trade your own life savings on some “exchange”. Not for other people, not other people’s money. You for yourself.

Suddenly, you really want to have every single line of your code, at any level of abstraction, to be absolutely correct (and, ideally, even to have been proven so)! Why not, one could generate Haskell code from Coq!

But how do you actually write such kind of code? How would you make all the necessary decisions at all levels?

It is in this situation that the time (money) and effort spent for studying The Classic Computer Science begin to pay off.

Suddenly all the foundational concepts, such as Modularity, Immutability, Abstraction Barriers, Strong Typing and especially Pure Functions (as in pure mathematics) start to make sense to you.

Some notions, like Partitioning and Nesting and assumed Immutability are the basic building blocks of Life Ltself, and go even deeper, into the so-called “fabric of the Universe” which underly and “establish” The Causality Principle itself.

Everything proper abstraction has to traced back to the aspects of reality from which it has been generalized (just as Sets or Numbers) or “Arrows” (directed graphs). Anyway, whatever.

So, how would one even approach such a task? Well, from the first principles.

One of them is “Data Dominates”. It goes as deep as “Everything (in the Universe) Has a Structure”, and implies that algorithms almost always “naturally” follow.

Another principle says that “Everything Is a Process”, and that processes have a shape. Mathematical and general Recursion have a shape of a spiral, not just a loop.

What a tip of an arm of a clock is “painting” is a spiral, not a circle, and the modular arithmetic is about points on a spiral (which appears as a circle).

All these detours, by the way, aren’t useless or redundant - they show you how the best proper abstractions produced by humanity work.

In so-classed Computer Science the most central and the most fundamental notion is how mathematician have created properly generalized abstractions long before any computers – with a set of values and a set of all possible operations.

It was so “right” that the notion of Sets themselves has been defined in this very way. Peano’s Numbers are another example.

Of course, it was a proper generalization which captures how the Mind of an external observer “works” (because the Universe has its “laws”).

This is what our Abstract Data Types are and ought to be - A set of values (defined by some set of properties – “such that”, and a set of operations (interfaces or type-signatures).

This is the connection all the way down to What Is.

This is what (and how) our own “types” (Algebraic and Abstract) which captures concepts of the problem domain have to be.

What we do with them is partitioning of the Universe of Discourse using Abstraction Barriers defined as Sets of Interfaces.

This corresponds to a cell-membrane of a biological cell.

Partitioning is crucial because it isolates and decouples and, most fundamentally, allows modifications (changes) without breaking the whole.

This is exactly what keeps huge and vastly complex systems (like Windows or Office) from falling apart and even what makes them possible.

No surprise here. The very same principles are behind biological systems, like (You), which are uncomparably more complex.

The idea to learn the underlying principles and “patterns” from Biology is at the core of the classic MIT tradition, which gave us MIT Scheme and everything that it is based upon.

If one would realize and use just these principles one already would be way better off than an average webshit “developer”. This, however, is only beginning, a tip of an iceberg. CS is wast and already encompass several “traditions” within.

Almost everything is reducible to particular arrangements of “arrows”, and those, in turn, form distinct patterns.

The early LISP guys have captured some with their box-and-pointer diagrams at the level of “the shapes of the data”.

The classic algorithm charting techniques have captured some more (at a different level of “shapes of sub-processes”).

The “Category theory” tried to capture all of em.

For us there are these generalized patterns:

  • ,
  • |
  • ->

and nesting and currying of these.

They are at the level of types as well as at the level of code. No surprise here. The symbolic notation used to describe logic are just these arrows replaced by the horizontal lines, and commas instead of currying.

Currying, of course, captures the notion of a “join” of one or more arrows - necessary and sufficient coming together in a some locality.

The neural networks, again unsurprisingly, has been built out of the very same building blocks, with partitioning and nesting. This is not because we “repeat ourselves”, but because “The Reality is One” and this can be “seen”.

Everything in CS, mathematics and logic is reducible to these arrangements of arrows (because this is how Causality Itself looks like).

This is what a proper programming (instead of “coding”) rests upon.

Immutability

Volumes have been writtern. It just pays off greatly if one defines everything in terms of pure functional language (or a pure subset) using only immutable data stractures (as in Clojure).

The resulting properties of such definitions are technically the same as wiht mathematics or logic, so one writes an “executable” pure math or pure logic (which is what GHC is an implementation of).

There are also Agda and Coq which could formally verify that your pure code (some modules at least) being “proven correct”.

All pure languages have the same basis (the Simply Typed Lambda Calculus) which, in turn, is a proper capture of a universal notion (including the necessary notion of an environment).

An interpreter of the Lambda Calculus is a universal machiene (which uses the fundamental notions) and this is why these MIT professors wear such funny hats and clothes on TV.

Again, everything is reducible to the patterns of dots and arrows (joins and forks in a directed acyclic graph), just like the information-processing strucure of the brain.

Currird functions a -> b -> c -> d shoud just be pictured as a “join” of a, b, c" (from differnt "directions") into a "dot" (an event) which emits ~d.

The premises and a conclusion have the same shape. Again, the notion of Necessity and Sufficiency (as in a chemical reaction) has been captured there. Or crossing a treshold within a neuron.

Where it goes form here?

At a “higer level of abstraction” we have events, which are conceptually simialr to “things” because they could be categorized just like things in Sets (using the “such that”) notion.

An event can be described by a tuple. Even 1-tuple.

The questing of identity is subtle (it is an exact location, which implies time, because the location is never the same). For us it is a location and (,) a timestamp.

They (more precisely - their observations) are collected in a log (an append-only file) Each entry can be conceptually viewed as a tuple. What wasn’t oberved didn’t happen.

A tuple is the simplest structured (non-atomic) and ordered (unlike a Set) data type. The ordering is necessary for actually writing down and accessing the elements of a tuple.

Every list has to be written down on a paper in some order (serialized).

Each row of a table is a tuple. Each row is an “example” if it correspond to a single distinct observation of an event.

It is a single recording of an event (from a log) and a “record type” is just a particualr representation (in order to store it or “write it down”).

When all the slots are number (ideally being normalized) it can be a row of a matrix. A “single training example” in the context of ML.

Again, each row is an “example” or a recording of an event.

A “record” is a “named tuple” with access of the elements by name (associated symbol), not by an offset (in bytes). Conceptually, “access by name” discrds the notion of an actual order (in a storage).

A set of tuples (of the same type) is, thus, the most general non-atomic type, and a Set of attributes (or properties) is the most general notion.

Embrace and design for changes

The Programs you write should be used for long time, otherwise why bother?

This implies they are never “finished” and have to extended and maintained.

A long-living program “stabilizes along abstraction barriers and corresponding stable interface”. Just like GNU Emacs or an OS such as Linux. Or MS Excel.

This means that stable high-level interfaces and modules are the main concerns.

Ideally, each high-level ADT (that represent a distinct concept from the problem domain) should live in its own module.

Embracing and optimizing for upcoming changes is the most important idea.

Our medium, unlike painting, sculpture or architecture is extremely maliable and lots of changes are at least possible. One cannot change a building or a sculpture (at late stages) or even a painting (signigicantly).

With program code we can change almost everithing, except, perhaps, very stupid architectural decisions, such as using async libraries everywhere.

The last 60 years of PL research and the modern practices of lartge corportations have taught us 4 fundamental things:

  • Disciplined modulatity (and strict discipline in general)
  • Static typing (facilitates changes, makes it less costly)
  • Interface versioning (stable, even immutable interfaces)
  • Immutable/persistent data (still esoteric)

Dynamically typed languages are cool and enable really fast prototyping, but then everything will become as mess. Look at Neovim’s Lua codebases. They all going fast and thus buggy as fuck.

Four our small progects (there is a limit to our cognitive capacity) the mantra is “ABC - Always Be Compiled” or just never leave a project in a inconsistent state.

Testing

Changes also imply mandatory extensive testing, including a regression testing. Testing is tedious and boring, but it is absolutely necessary.

The good news is that the properer TTD practices done right (at an interface level) allows writing tests before code, which, in turn, is related to exploratory programming and REPL-like quick experementation.

The main principle about testing is that one never writes tests after the code, but before the implemetation details.

Proper tersting (before code) tests the validity of inteterface-level constraints and invariants before any implementation is being programmed.

Remember that having non-leaking abstractions (proper abstraction barriers) will allow to have multiple implementations to coexist and be easily swapped and reused.

Layers of DSLs

At a system level it has been shown multiple times (independently) that there is nothing better than to organize large systems as layers of embedded pure-functional DSLs.

This is the principle of “immutable interfaces” at work. Hardware graphics pipelines is where it really shines. MATLAB’s Matrix DLS is another golden standard.

X11, TeX and GNU Emacs are famous for their proper layered structure.

Languages

  • Ocaml 5 (Modularity and discipline)
  • Scala 3 (wonderful testing DSLs as libraries)
  • Haskell 9.6+ (proper UTF-8)
  • Agda or Coq
  • TLA+

These are, despite memes, way, way superior to any commercial imperative crap, like C++, even with all the tooling.

OK, it is easy to rewrite in C++ once you have a pure FP prototype working and tested. And Rust is already a better choice.

The real problem

This was the easy part. There is almost never any problem with how to write (given familiarity with a classic CS literature).

The real problem is what to write. How do you even start to begin?

Discrete-time signal processing? Kalman filters and other mathematical basis of the radar tech?

Deep Learning

Non-bullshit deep learning (it is infested by Chuds like a fresh pile of poo with flies) has a couple really fundamenral principles behind it.

  • improvemnts in observed behavior without being explicitly programmed
  • automatically learning the “parameters” (without being selected by hand)

At the highest, conceptual level this is big. The system learns a nearly optimal representation from the data.

All stupid memes aside, it allows to actually do things which are way beiond our tiny mental (cognitive) capacities.

There are challenges of a similar magnitude:

  • how not to learn noise
  • how not to overfit
  • how to consistently re-learn on the new data (withot regressions)

The answers are that one cannot apply Deep Learning to anything, only to a well-defined problems in a stable, fully-observable and preferably discrete environment.

The problem is, all such environments (models) are gross over-simplifications. The real challenge is to come up with one that is actually useful and earns you money.

The key to successful Deep Learning applications is to have a data-set which adequately measures (captures) the phenomena and in not lying to yourself.

This is exactly why seemingly “obvious” applications of the learnign algorithms to the financial markets (by Chuds) yeielded so far only bullshit (markets are the exact opposites of stable and fully-observable environments).

The real challenge is to come up with a set of measurements that actually measure and prartially capture at least some aspects of the social Causality behind recurrent (re-emergent) patterns.

Actual and accurate measurements of anythig non-imaginary, not just any “big data” (meme) is the key to success.

At the highest level this is “To observe (measure and record) things as they really are”.