Haskell — a higher order language

The thesis here is that Haskel is not just one of many functional programming languages — it is a different, more advanced programming paradigm.

Haskell is indeed an elegant functional language, but calling Haskell “a functional language” is like calling a skyscraper “a dwelling” — while technically correct, it does not adequately describe how the latter is much more than just a place to live.

What defines a programming language? From the point of view of category theory, there are two major components of each programming language: data types and transformations between them — in category theory terminology, “objects” and “morphisms”.

The first claim here (that must be challenged) is that all programming languages but Haskell (and more recent Idris) are based on “morphisms” — code, procedures or functions that transform and manipulate the data. Data types in these languages play the secondary role — to ensure validity and to improve predictability of the “morphisms”.

Haskell, being a functional language, counterintuitively, is not based on functions — it is based on types, or “objects” in category theory terminology. Types ensuring the validity of transformations almost seems secondary in Haskell (however useful), while the primary purpose of types is to formally describe the system model and the relationship between the elements of the system (including functions that also have types).

But a bigger distinction between Haskell and other languages is in the nature of the language semantics. The second claim (that also must be challenged) is that while other languages have semantics tightly coupled with the syntax — the meaning of the code is defined by its grammar, Haskell semantics is defined by the combination of code and context (e.g., created by the types that belong to Monad class). In this way, Haskell is much closer than other programming languages to the natural human languages that also have semantics defined by the combination of grammar and context (see interpretive and generative semantics of human languages).

For example, a simple sequence function that is defined as:

can mean different things depending on the context that is defined by m.

Applied to IO it can mean performing IO actions in sequence:

returns a single IO action that resolves into the list of 2 strings.

Applied to the list of instances of Maybe type, it would check that all of them contain some value and either return Just list of these value or Nothing if any of them is Nothing:

Applied to the list of 2 lists, it will perform indeterminate computation and return all possible permutations of list items where the first item comes from the first list, and the second — from the second list:

Context-dependent semantics of Haskell code makes Haskell more difficult to learn. As the same syntax can mean many different things, achieving fluency requires more effort than with other languages. But it also makes Haskell infinitely more expressive than any other language — you can implement any new semantics you want by adding the new context to the same code. Therefore, while Haskell requires more investment from you than other programming languages, the return on this investment is infinitely higher.

Some Haskell books (e.g. LYAH) and lectures (e.g Penn course) do not capture this fundamental distinction well enough. Instead, they focus on the functional nature of Haskell, and present Monad as almost some work-around to allow using pure functions for context-aware computations (IO, State, indeterminism, etc.). Unfortunately, it creates a barrier to entry for the new developers, because when people are asked to make a larger than usual investment to learn yet one more functional programming language with quirky syntax, this investment is difficult to justify without understanding first that Haskell is a more powerful programming paradigm. How many people abandoned Haskell before grasping its power?

A good book that explains how Haskel is a higher order language is Haskell in wiki-books. Once you get over “Understanding monads” section, the Haskell advantage should become apparent.

If you want to see some relatively simple magic you can do with Haskell, watch the talk by Paweł Szulc at Lambda World’19, particularly where he talks about Servant — the library to create REST APIs in Haskell. Before you write a single line of implementation code, you can get the whole API definition from a single type definition (I am replacing alpacas from Paweł’s farm with users here):

And before you even start implementing this API you can get client functions to call this API with a few lines of code:

With just a few annotations you can generate API docs from UserAPI type:

To run this server you just need to implement it, the mock implementation is very simple, but the Haskell type system ensures that the type of implementation is correct (Server UserAPI that is based on UserAPI type):

The above does feel like magic!

Morphism-based programming languages (i.e., all other languages) force programmers to model the whole system outside of the code — using SQL schema, JSON schema, diagrams, etc. Type-based languages (Haskell and Idris) allow for type-driven development, when the whole system can be modelled top-down with algebraic data types, rather than bottom-up with functions as in other languages.

Haskell being type-based language with context-dependent semantics is a higher order language that is almost one of a kind — there seems to be no other mature programming language that allows the same level of expressiveness as Haskell does.