
Algebra Driven Design - agentultra
https://algebradriven.design/
======
g_delgado14
The top comment on yesterday's post on the Keli language
([https://news.ycombinator.com/item?id=24331635](https://news.ycombinator.com/item?id=24331635))
sums up FP's failure to become mainstream pretty clearly IMO:

> The other reason is that many FP users are too enthusiastic about creating
> abstractions. This is of course something that FP is exceptionally well
> suited for. An api that was written to simply process a list of Orders into
> a Report might be abstracted into a fold on some monad, which at first seems
> a great idea. But if you're not careful, readability suffers a lot. It's
> much easier to get to know an application when its code deals with business
> objects that you already understand well, than to read hundreds of lines of
> code that deal only with abstractions.

Industry programmers didn't sign up to learn about category theory. They do
what they do because they like building things. There is a subset of those
Industry Programmers that does indeed like learning about category theory and
all of these other concepts necessary to grok languages such as Haskell - but
it isn't a critical mass by any means.

That's why I think languages like Elm are a good example of "the sweet spot"
of FP languages. Yes, Elm lacks the horsepower that other pure FP languages
have, but at least it doesn't lead a developer to think "hey, I didn't sign up
to learn about Arrows and Monads. I just want to write a TODO list".

~~~
centimeter
You don’t have to know category theory to use Haskell. You have to learn some
basic concepts like monads, but complaining about that is like complaining “I
don’t want to use Java because then I’d have to learn what an object is”.

~~~
g_delgado14
I disagree that objects and monads are the same level of building block in the
respective paradigms.

Objects <> Java and functions <> Haskell might be a better comparison.

Not to mention that there's already a person's intuition about what an
"object" might be before they even learn programming. But there's no real-
world analog to what a Monad is. So, yes, you do get into the situation where
a programmer will say, "what? I didn't sign up for this" when being told to
learn Monads to use Haskell.

~~~
centimeter
There’s also no real-world analog for a For-loop, but it’s still not a
credible complaint to avoid learning C.

Also, just because java objects are called “objects” and not some other word
with less colloquial meaning doesn’t mean that they actually map well to real-
world objects. Fully understanding the true semantics of Java objects is at
least 100x as complicated as fully understanding the true semantics of monads.
The only thing it’s easier to do with Java objects is to delude yourself into
thinking you might understand them, because they have a familiar name.

~~~
jheriko
thats not true at all, repetition is natural.

map is also quite natural, but isn't it telling that the way a human will do
this on paper is by reptition of the same task in sequence... i.e. a for loop.

> The only thing it’s easier to do with Java objects is to delude yourself
> into thinking you might understand them, because they have a familiar name.

i'm not sure why you consider this 'delusion'? that familiarity of name and
concept is precisely why its so easy to learn.

~~~
codygman
> map is also quite natural, but isn't it telling that the way a human will do
> this on paper is by reptition of the same task in sequence... i.e. a for
> loop.

Would they?

------
peterlk
> 10x is often cited as the magic number beyond which technology is good
> enough to overcome network effects. I'm personally convinced that functional
> programming is 10x better than any other paradigm I've tried

Better for who? Bad code that ships is better than good code that doesn't.
From a business perspective, I don't care if it's written in COBOL as long as
it ships.

The critical missing piece in the functional argument is an example (or
probably several) where a company using functional programming consistently
outperformed one that wasn't. By default, the business will be opposed to
using anything that isn't one of the big programming languages because
haskell/scala programmers are expensive. Why would I pay a bunch of expensive
haskell programmers to build a chat app? I could build something that got me
80% of the way there for 30% of the cost.

I think Haskell can flourish in places where correctness matters - fintech,
factory control systems, and weapons come to mind. But in the vast majority of
places that employ programmers, correctness doesn't actually matter. One
argument for this is that requirements change so often that "correct" is
impossible to define, so the overhead of being correct is actually a bug, not
a feature.

With all that said, I do wish that we had better software, and that
correctness mattered more. I like functional programming, and I think learning
it can make any programmer better.

~~~
leephillips
“Bad code that ships is better than good code that doesn't”

Maybe better for your bottom line (no criticism, we all have to eat), but not
better for the world. Look around at our software universe: bad code that
shipped, everywhere.

Bad code that ships gets us Windows.

~~~
jcelerier
> Bad code that ships gets us Windows.

as much as an enthusiast linux user I am, I'm pretty sure that the world would
be a worse place without DOS & Windows

~~~
ragnese
How so? I mean, obviously it's impossible to make a decent educated guess
since basically the entirety of most peoples' interactions with computers
stems from the near-monopoly Microsoft had on personal computing in the 90s.
But I'm still curious to know what you predict would be different if MS didn't
strike their deal with IBM.

~~~
Jtsummers
MS Window's presence in the market made PCs true commodities and drove down
the price for home and office computers in a way none of their contemporary
competitors would have achieved.

Most of their competitors were tied to hardware, and received a lot of their
revenue and profit from the combination of hardware and software sales. MS
only needed to sell the software, and let HP, Dell, Gateway, and others
compete on hardware prices. This probably put more computers out there (within
that time span) than would have been achieved without them.

------
jinwoo68
I love Haskell and appreciate its abstraction power. But recently I started to
think that one of the reasons that prevent it from becoming more popular is
that the community focuses too much on "mathematical" abstractions. Almost
every abstraction becomes a mathematical one. "Oh, this thing turns out to be
a Monoid! Let me abstract it." "Oh, I can simplify this using Traversal", etc.

They usually make perfect sense and useful abstractions, but at the same time
they scare many programmers away. Especially non-math-savvy programmers will
be easily turned away when they see code that is heavily abstracted in a
mathematical manner.

I also come from Lisp and Lisp focuses on building a language using the
terms/concepts from the given problem domain. And when you do it right, it
makes the code very natural in that specific problem domain and any domain
experts can understand the code easily.

Haskell communities do it very differently by making everything a mathematical
problem, and it's only math experts who feel comfortable with the code.

~~~
ghj
Mathematical abstractions are often at the wrong level of abstraction.
Mathematicians mostly care about value semantics but programmers need to care
about how it's realized in hardware too.

For example, sure, you can think of a list as a "monoid" where the add
operator is concatenation of two list. But adding two lists is not a fast
operation even using specialized functional data structures. So making
concatenation a primitive for equational reasoning just results in really slow
code.

~~~
contravariant
I'm confused, with the right data structure concatenating lists is an O(1)
operation.

~~~
ghj
You're probably thinking of storing it as some linked list but that doesn't
work with mathematical abstractions (which is my point).

For example in mathematics if you write "C = A + B" and then you ask what A
is, it's still always going to be the same.

To make this work in programming you basically have to make all your data
structures persistent[1]. AFAIK you would need a store the list as a finger
tree or something if you need fast concatenation and that will still only be
O(log(n)) [2].

[1]
[https://en.wikipedia.org/wiki/Persistent_data_structure](https://en.wikipedia.org/wiki/Persistent_data_structure)

[2]
[http://hackage.haskell.org/package/fingertree-0.1.4.2/docs/D...](http://hackage.haskell.org/package/fingertree-0.1.4.2/docs/Data-
FingerTree.html#v:-62--60-)

[3] [https://stackoverflow.com/questions/28406512/why-does-
concat...](https://stackoverflow.com/questions/28406512/why-does-
concatenation-of-lists-take-on)

~~~
leafboi
In math everything is persistent/immutable anyway, so persistent data
structures are a given when working with purely mathematical abstractions.

There is a memory issue because of this, but this problem isn't exclusive to
FP languages. Many languages solve this with something called garbage
collection.

~~~
leafboi
The very definition of pure FP (which is basically just programming founded on
the principles of mathematics) rest foundationally on just a program that is
immutable and has no side effects. Those are the only two requirements needed
to do FP.

Immutability is therefore the axiomatic foundation of FP.

------
codygman
You might have been bitten by this before:

    
    
        1. Make it work
        2. Make it right
        3. Make it fast (uh-oh your nice design prevents performance optimizations, time to scrap it)
    

The reaction to that is usually to think more about performance ahead of time
so you don't get trapped by your theoretically perfect design when the real
world comes crashing down.

With your hard-won experience you do away with those childish notions of being
able to make a perfect elegant design where you don't have to worry about
performance until the end.

The most valuable thing you'll find in Sandy's book is that you can actually
ignore performance until the end and nearly always (always maybe?) be able to
make it fast.

You can regain your optimism from your younger years before the bad
experiences and resume this path:

    
    
        1. Make it work
        2. Make it right
        3. Make it fast
    

I think it goes without saying that I _highly_ recommend Sandy's book and
think it could be the way forward for quickly writing correct, elegant
(composable/re-usable!), and __FAST __programs.

~~~
leafboi
>theoretically perfect design

We have no metric to use to quantitatively score one design as something
unequivocally better than another design.

This is the first thing you will need before you can prove one "design" is
"better" than the other. Until than we are doomed to go in circles and have
endless debates.

I believe even if we do find some quantitative measure on program "designs" it
won't be rating something as "better" or "worse" it will likely be metrics on
many dimensions measuring tradeoffs.

~~~
codygman
When you design software focusing only on the business logic and domain the
end result will be better than if you have to do it while juggling
implementation and performance concerns.

> We have no metric to use to quantitatively score one design as something
> unequivocally better than another design.

Given the current state of software development, it's not fair to place that
burden of proof here when it's not used elsewhere.

~~~
leafboi
>When you design software focusing only on the business logic and domain the
end result will be better than if you have to do it while juggling
implementation and performance concerns.

Do you have a foundational proof for this? What are your axioms and theorems?
A qualitative description (that you have provided) is open for debate. I can
say the opposite and supply you with an endless chain of examples while you
come at me with couter-examples and we go nowhere.

>Given the current state of software development, it's not fair to place that
burden of proof here when it's not used elsewhere.

The entire mathematical community has this burden placed on them. The entire
scientific community has lesser statistical validations placed it. The
programming community has endless design pattern debates online as the burden.

------
commandlinefan
This is something I spend a lot of time thinking about myself - it _seems
like_ functional program ought to be > object-oriented program which ought to
be > procedural programming. However, I've almost never seen a functionally-
designed application "in the wild" and honestly, it's pretty rare to even see
an object-oriented one. It seems like every program I ever dig into is mostly
written procedurally, even if it's written in a language that supports higher-
level abstractions. And, for the most part, software works. As much as I love
the concept of pure functional programming, how do we really know that
"functional programming is better" and that's not just wishful thinking on our
part? Looking forward to digging into this - hopefully the author can make a
better case than others have.

~~~
leephillips
Neither paradigm solves the expression problem. This forces people to break
the paradigm as the code grows. Look at the code in some Julia packages, and
you will see good use of abstractions around a language design where the
expression problem does not exist. This is practical stuff, being used in
applied scientific research on a large scale.

~~~
marcosdumay
From the wikipedia:

> The expression problem is a new name for an old problem. The goal is to
> define a datatype by cases, where one can add new cases to the datatype and
> new functions over the datatype, without recompiling existing code, and
> while retaining static type safety (e.g., no casts).

Why should I care about recompiling? That's an implementation detail.

Taking the compilation stuff out, it looks very similar to classy lenses.

~~~
lastofus
> Why should I care about recompiling? That's an implementation detail.

Sometimes you don't have access to 3rd party src code you call into, hence why
you can't always modify and recompile it.

~~~
adamnemecek
Its more about the modification rather than recompilation.

~~~
marcosdumay
But type classes solve the modification problem. (Even tough no language that
I know of solves the recompilation.)

------
Xophmeister
This looks interesting and the "freebie" is quite extensive at 80 pages. It
would be nice to have a full table of contents to see what more you can
expect, rather than the "executive summary" of what you could hope to learn.

------
Chris_Newton
As both a mathematician and a programmer who often works on projects where
high reliability is essential, I want to like the concept behind this book.
However, based on the website and sample chapters, it’s not clear that there
will be strong arguments made here about either scalability or performance,
which are the usual practical problems with trying to employ formal methods
and very “mathematical” abstractions. Sadly, the early repetition of the usual
faux quicksort example _and_ the casual dismissal of arguments by “purists”
about the difference is going crush the author’s credibility among a large
group of programmers by the end of page 7, which is not a good omen.

~~~
bmitc
Do you mind sharing what industry you work in and how you got there? I am
mainly caught by "as both a mathematician and a programmer who often works on
projects where high reliability is essential". I was a mathematician (or more
strictly am a failed mathematician) who also does software, and so I am always
curious what other domains people with this background work in.

In general, I am turned off as well from the abstractionauts in the software
world, particularly those found in the Haskell realm, and highly prefer more
pragmatic functional languages like F#, Racket, and Elixir/Erlang.

~~~
Chris_Newton
_Do you mind sharing what industry you work in and how you got there?_

I’ve worked on software in a few different industries, but the ones that
needed particularly good reliability were mostly related to hardware deployed
in challenging environments. For example, it’s never good to discover a bug in
production when your firmware update process involves helicopters. :-) I’ve
also worked on software that used quite intricate data processing algorithms,
where any bugs could manifest as subtly incorrect behaviour that might not be
noticed until it was too late and some serious failure had been caused.

I didn’t specifically pursue these kinds of projects, they just happen to be
common themes in the roles I’ve taken over the years. In time, I developed an
interest in tools and processes for producing software that is significantly
more reliable than much of what our profession produces, yet not necessarily
on the level of say threat-to-life or running-a-satellite code where extreme
measures might be justified almost regardless of cost. I firmly believe that
even with the inevitable pressures driving commercial software development,
the standards in our business could be much higher than they often are today,
and that much of the problem is due to people — developers, managers, users —
not realising what else is achievable or what it would really cost.

------
li4ick
I'm starting to think that every thread about FP is pretty much identical on
HN, especially when Haskell is involved. If you still need a ton of push to
try it out, you'll never get it. If decades upon decades of provably superior
concepts haven't convinced you, just give up. Just go and get hyped when the
next minor FP feature gets integrated into your favourite language, something
that's been used in Haskell/Erlang/etc. for 20+ years.

~~~
mrkeen
> I'm starting to think that every thread about FP is pretty much identical on
> HN

Spot on.

Where is Haskell actually used? No I meant apart from Facebook and Uber and
Klarna.

> Just go and get hyped when the next minor FP feature gets integrated into
> your favourite language

We already have immutability in Java - why, the designers themselves made
Strings immutable [1]

We said goodbye to nulls in Java [2] but in case you really don't like nulls
you can also say goodbye to them by switching from Java to Kotlin, which
doesn't have them [3] but also does [4].

If you want to cut down on some boilerplate (without moving to Kotlin), you
can try type inference in Java [5]:

> For example, consider the following variable declaration:
    
    
        Map<String, List<String>> myMap = new HashMap<String, List<String>>();
    

> You can substitute the parameterized type of the constructor with an empty
> set of type parameters (<>):
    
    
        Map<String, List<String>> myMap = new HashMap<>();
    

Go got rid of Generics which made programming so much simpler. I can't wait
for its new Generics feature though.

But if you really need that functional stuff - the best thing writing Java
code is that it runs on the JVM, so you can code in Scala instead. And if that
argument doesn't make you want to code in Java I don't know what will.

[1] [https://javarevisited.blogspot.com/2010/10/why-string-is-
imm...](https://javarevisited.blogspot.com/2010/10/why-string-is-immutable-or-
final-in-java.html)

[2] [https://programmer.help/blogs/finally-i-m-happy-to-say-
goodb...](https://programmer.help/blogs/finally-i-m-happy-to-say-goodbye-to-
null-say.html)

[3] [https://medium.com/kayvan-kaseb/say-bye-to-
nullpointerexcept...](https://medium.com/kayvan-kaseb/say-bye-to-
nullpointerexception-in-kotlin-c8f0bae2c773)

[4] [https://stackoverflow.com/questions/50427490/nullable-
type-s...](https://stackoverflow.com/questions/50427490/nullable-type-still-
throw-nullpointer-exception-at-kotlin)

[5]
[https://docs.oracle.com/javase/tutorial/java/generics/genTyp...](https://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html)

~~~
li4ick
I use Haskell because it actually delivers on the promise of software
reusability. In his book, John Ousterhout wrote a wonderful phrase:
"increments of software development should be abstractions, not features.". I
completely agree.

Even though the JVM ecosystem is great, I dislike the languages that run on
it, Clojure being an exception. To filter out OOP, it fundamentally abstracts
the wrong thing. Modules should abstract functionality, not data. And that's
why I don't want anything to do with Java.

------
jheriko
> I'm personally convinced that functional programming is 10x better than any
> other paradigm I've tried.

The failing is having a simple model that assumes that any one paradigm is
ever best.

A multi-paradigm language will always have the capacity to be better, or
equal, by any metric.

I also strongly disagree with this sentiment based on experience. There are
some tiny niches where functional programming is particularly useful, but
outside of them the code is classically difficult to read, write or debug....
a problem made worse by the, very honestly, absolutely appalling quality of
almost all example code - normalising one letter variable names, squeezing
things onto one line and all kind of other terrible practises.

these are deeply serious problems that fp fanboys and academia seem to glaze
over, presumably from a lack of real world experience, or appreciation of how
valuable these qualities are ...

~~~
codygman
> There are some tiny niches where functional programming is particularly
> useful, but outside of them the code is classically difficult to read, write
> or debug

What niches are these where FP is "classically difficult to read, write or
debug"?

~~~
non-entity
I think they're saying the opposite, that FP languages are difficult in
general and only useful in a few niches.

------
g_delgado14
Someone wrote a comment in this thread saying that Haskell's strength is
"rigorous correctness". Ok sure, I agree that generally your program is going
to be more correct with Haskell than with, say, TypeScript. But that doesn't
preclude a TypeScript program from ever being as correct as a Haskell one. One
limitation might be the additional boilerplate due to the inability to
abstract as much as Haskell. But if more boilerplate translates to greater
readability (i.e. less abstraction & much closer relation to the problem
domain) then I would argue that the added boilerplate is justified.

Hence I don't really see, "rigorous correctness" as a good selling point for
using Haskell since company culture tends to affect correctness just as much
as the language a team uses.

~~~
gmfawcett
That's a pretty big "if", though. Boilerplate is generally noisy, and it can
be challenging to encapsulate it well enough (e.g. behind function boundaries)
that the remaining code is high level and business-logic oriented. Company
culture can only go so far (unless you're willing to pay the full tax, and
maintain your code in the costly, slow way that e.g. NASA and other life-
critical systems developers would).

You can get halfway to Nirvana just by using a language that self-manages
memory and has some kind of exception system (error handling at a distance);
something like RAII (automatic lifecycle management, or automatic destructors
in a pinch) can be a big help, too. Now, at least, all the systems-level
boilerplate can be omitted from your mainline code.

But high level, business logic pitfalls are hard to encapsulate, and
especially so in a dynamically typed program. Documentation becomes critically
important (don't ever do X before you do Y), as rigorous unit tests for chains
of actions can sometimes be difficult to write. A good, type-level model of
your program can be a helpful set of safety rails when refactoring a a large
and complex code base, and a rich type system gives you more tools to build
those rails to fit the the solution you're building. As a (weak) example, if
your type model never lets you read from a file that's already been closed,
that's one less thing you have to cover in testing or documentation -- or more
importantly, it's one less thing you have to _remember_ to test.

At scale, having multiple ways to introduce structure into an otherwise
chaotic (or _arbitrarily_ structured) code base is a win. Building a good
type-level model is one smart way to achieve that.

------
revskill
I prefer a book on api design with haskell rather than this theoretic book.

~~~
codygman
This "theoretic book" can help you design a very good api. If you mean REST
api's by chance, remember those were theoretic once too!

------
harry8
I'd be more convinced if the author linked a bunch of software they'd written
before writing yet another haskell tutorial.

10x? We're way above 10x in the ratio of haskell/functional/monad tutorials to
running applications. If touting that yours is "the one" and we should skip
over the tens of thousands of others out there, some supporting evidence might
be useful.

Applications written in haskell you can run on your computer for doing
something other than programming is still a list that you can count on your
fingers. Please let me be wrong about that and list them if I am. I'll be
delighted and wildly enthused.

~~~
codygman
> Applications written in haskell you can run on your computer for doing
> something other than programming is still a list that you can count on your
> fingers.

Before you make such strong claims, you should at least try and validate
they're true. Please stop spreading this lie.

~~~
pkphilip
You could counter that claim by actually providing a list. You will quickly
find that there are far more applications written in Java, Go, NodeJs, Python,
Ruby and C/C++ than in Haskell.

EDIT: Please see the TIOBE rankings just to see where Haskell is. I think it
is currently at 43

~~~
codygman
Someone already did and the goalposts just got moved again:
[https://news.ycombinator.com/item?id=24352585](https://news.ycombinator.com/item?id=24352585)

