
Hask is not a category - snaky
http://math.andrej.com/2016/08/06/hask-is-not-a-category/
======
fmap
The article is spot on. Even the proposed construction of a category by taking
the quotient of closed terms under observational equivalence probably wouldn't
really work. You may be able to get a category this way, but it just wouldn't
have nice properties. Reasoning in the presence of selective strictness is
hard...

On the other hand I don't think it's actually very relevant. Category theory
in the context of haskell is a source of ideas, not a tool for formal proofs.
Stream fusion and related constructions such as free monads are wrong if you
take seq and undefined into account (and don't even start with actual impure
features such as unsafePerformIO). So the "real" category Hask would tell you
that these constructions don't exist.

The category that people seem to think of as Hask seems to consist of the
total functions modulo the obvious observational equivalence. This is very
well behaved and I'd argue that it's a great source of ideas for practical
programming patterns.

~~~
greydius
> Category theory in the context of haskell is a source of ideas, not a tool
> for formal proofs.

My thought as well.

It seems Haskell gets criticism from both ends of the spectrum: it's either
too academic to be practical or too practical to be academic.

~~~
catnaroek
> It seems Haskell gets criticism from both ends of the spectrum: it's either
> too academic to be practical or too practical to be academic.

How about “its abstractions leak in ways the community doesn't want to
address”?

And “too practical to be academic” is bullshit. There's nothing more practical
than an elegant language whose actual semantics matches the way you think.

~~~
codygman
Can you give some examples of abstractions that leak which the community
doesn't want (or hasn't wanted) to address?

~~~
catnaroek
Let's take a basic one: Haskellers would tell you with a straight face that
`Either a b` is really the coproduct of `a` and `b`. It's not.

If you bring up bottom, they'll tell you “oh, let's just ignore it”. Well, the
only way you can ignore it and not be wrong, is to arrange things so that a
variable never stands for bottom - that is, to use a strict language.

Don't get me wrong, Haskell's abstractions are nice - or they would be, if the
premises they are built upon were true.

~~~
vilhelm_s
There is one more way to make sure that variables do not stand of bottom --
make sure that you only write terminating functions. Then the equational
theory for strict and lazy evaluation becomes the same.

I think this is the main reason that people don't worry too much about bottom:
in practice all functions should terminate anyway. If your program gets stuck
in an infinite loop, you probably have bug.

~~~
catnaroek
> in practice all functions should terminate anyway

Sometimes they terminate with an exception.

------
wyager
God, I'm so tired of this boring platitude. Every criticism of Haskell not
satisfying category laws (of which there are many) are of the form "undefined
breaks things". Obviously! How would a runtime-error-inducing concession to
practicality _not_ break things? Haskell also fails to satisfy the category
laws if I make unsafe FFI calls or use unsafePerformIO to crash the program
randomly. Thus is the nature of programming languages.

~~~
seagreen
But as Haskellers we _are_ concerned about unsafePerformIO et al. -- this is
why we have the SAFE pragma.

~~~
tome
Agreed. But it doesn't need Andrej Bauer to point it out to us.

------
vilhelm_s
Dan Piponi wrote an article about this: "What Category do Haskell Types and
Functions Live In?" ([http://blog.sigfpe.com/2009/10/what-category-do-haskell-
type...](http://blog.sigfpe.com/2009/10/what-category-do-haskell-types-
and.html))

He says that the more fruitful connection between Haskell and category theory
goes in the reverse direction. Rather than trying to define a category Hask,
which would contain all Haskell programs including exceptions, "undefined",
out of memory, and so on, and then see if there are any general theorems in
category theory which would help us understand Haskell, we should do it the
other way around. Look at a particular small Haskell program, consider all the
different categories it could be interpreted in, and see if this gives us a
better understanding of category theory!

------
dietrichepp
I would like to see an analysis of Hask when restricted in one of the
following ways:

1\. Only strict functions (f ⊥ = ⊥)

2\. Only total functions (x ≠ ⊥ -> f x ≠ ⊥)

But otherwise, the notion that Hask is not a category is nothing new.

~~~
catnaroek
The problem is that the entire library ecosystem is built under false
premises. It's annoying, because you occasionally stumble upon an abstraction
leak, and then you need to take a really deep breath, climb down the
abstraction ladder (which is pretty tall in Haskell's case!), and look for the
exact place where something went wrong.

~~~
dietrichepp
I'm not convinced. All abstractions are leaky, you just have to decide whether
a particular abstraction is useful or not in spite of its leaks. I think the
problem you are talking about is the fact that Haskell code tends to have lots
of abstractions built on top of other abstractions.

While this is definitely a problem in some Haskell code bases, you will also
see your fair share of Haskell code which is closer to purely functional code
or closer to straightforward imperative code.

~~~
catnaroek
> All abstractions are leaky,

I can tolerate abstraction leaks when the cost of using the non-leaky version
is prohibitive. For example, I wouldn't want a language that constantly
reminds me that memory allocation can fail. “Memory is infinite” is just too
nice an abstraction, and I'm not going to let the fact it isn't true get in
the way.

But I can't live with a mismatch between the language's intended and actual
semantics. If the Haskell language, libraries and community promise me that
Hask is morally the category of sets, then it better be morally the category
of sets! Of course, this promise is impossible to fulfill in a language
without a typefully delimited terminating subset, so Haskellers better scale
down their ambitions to something actually realizable.

> I think the problem you are talking about is the fact that Haskell code
> tends to have lots of abstractions built on top of other abstractions.

No, I don't mind high abstraction towers - I actually like them, in fact! What
I hate is climbing them down because some abstraction leaked somewhere.

> you will also see your fair share of Haskell code which is closer to purely
> functional code or closer to straightforward imperative code.

Since when is imperative code straightforward? Reasoning about purely
functional programs: high school algebra, plus induction over datatypes.
Reasoning about imperative programs: Hoare logic. The facts speak for
themselves.

In any case, this has nothing to do with functional vs. imperative. It's just
“please don't impose cognitive dissonance on me!”

~~~
dietrichepp
That's a really disingenuous interpretation of "straightforward". If you don't
want to have a real conversation then just don't bother replying next time.

~~~
catnaroek
> If you don't want to have a real conversation

I wanted to have a real conversation, but, given the hostility in your
response, I'll stop.

~~~
dietrichepp
Hostility was exactly what I read in your comment about Hoare logic.

------
qwertyuiop924
Is this true? Probably, I don't know the math.

Do we, as Haskell programmers, need to care? No. If you want to learn Haskell,
forget Category theory, until you want to learn the theoretical underpinnings
of it. Focus on learning how Haskell ACTUALLY works, not how mathematicians
want it to work.

In short, learning category theory will likely help you learn Haskell about as
much as learning lambda calculus will help you learn Lisp. Maybe a bit less.

~~~
dllthomas
> If you want to learn Haskell, forget Category theory, until you want to
> learn the theoretical underpinnings of it.

Category Theory isn't very useful for learning the theoretical underpinnings
of the language itself.

~~~
qwertyuiop924
Oh. Wow. It's worse than I thought.

~~~
dllthomas
I'm not sure what you mean by that. Haskell, the language, is theoretically
built more on the lambda calculus and logic. Category Theory has served a
fruitful source of inspiration in the design of some languages (and in some
places provides a common vocabulary).

------
nshepperd
I wonder what the author thinks of "Fast and loose reasoning is morally
correct" (Danielsson, Hughes, Jansson, Gibbons. 2006.
[https://www.cs.ox.ac.uk/jeremy.gibbons/publications/fast+loo...](https://www.cs.ox.ac.uk/jeremy.gibbons/publications/fast+loose.pdf)).

~~~
jonsterling
That paper is just a bit of bureaucracy which demonstrates that total programs
behave the same in a total language as when they are embedded into a partial
language (which is an intuitive result, and it's nice that they worked out the
details!). It's also a nice demonstration of the logical relations proof
technique.

But sadly this paper is pulled out all the time by people who I suspect don't
understand what is going on, to justify sleight of hand & dodgy reasoning
which has little to do with the result in the paper. (Not claiming that's
what's happening in the above comment! But I bristle a bit when I see this
paper come up in amateur/Haskell circles.)

------
Chinjut
Do we not get a category if we take morphisms from A to B to be expressions of
type B with a free variable of type A (thus, morphisms are non-closed terms),
and composition of f with g to be substitution of g into the free variable in
f? This is automatically associative with proper identities, anyway, even with
a purely syntactic notion of morphism equivalence. Of course, one will
probably want to impose a coarser notion of equivalence to reason
categorically about Haskell in near-usual ways, and perhaps subtleties plague
all attempts to do so usefully.

------
KZeillmann
Is there a good introduction to category theory online that references
applications in functional programming? I never took a category class in
college and am looking to read up on it

~~~
buddhu
"Category Theory for Programmers" is generally excellent and quite easy to
read: [https://bartoszmilewski.com/2014/10/28/category-theory-
for-p...](https://bartoszmilewski.com/2014/10/28/category-theory-for-
programmers-the-preface/)

------
danharaj
It's well known that `seq` wreaks havoc on lazy semantics. Without `seq` it's
much easier to make it a category.

------
revelation
This is an awesome article about a novel, practical problem solved by Haskell.
Or rather I wish it was so my time wasn't utterly wasted.

~~~
danharaj
what did you expect from the title?

------
catnaroek
It's been known for quite a while that Haskellers live in a make-believe world
where totality is taken for granted, and Hask is morally the category of sets.

One possible fix is to read the call-by-push-value papers:
[http://www.cs.bham.ac.uk/~pbl/cbpv.html](http://www.cs.bham.ac.uk/~pbl/cbpv.html).
The danger is that they might want to switch to a strict language.

~~~
danharaj
Haskell* is essentially an extension of System F. System F has no set models.

* Need to enable a few extensions.

~~~
catnaroek
Oh, that's another thing that makes me really angry too: GHC's lack of
distinction between first-class polymorphism (functions from types to values,
à la System F(ω)) and second-class polymorphism (values, not necessarily
functions, that admit more than one type, à la Damas-Milner). But that's a
topic for another day.

EDIT: Also, I forgot, I haven't actually seen Haskellers use
ImpredicativeTypes much. Are you really sure that the predicative subset of
System F (just RankN types) has no set models?

