14 ms·
Haskell is not category theory
- mattpallissard 4y ago> However, if you are proficient with any functional language, especially if it is a dialect of ML, The one, true ML.
- Koshkin 4y ago;;
- runevault 4y agoI'm confused by his argument that Haskell functors are only endofunctors because everything is Hask. I thought that even if everything is part of one category, if the input is a different category that is a subset of the one category and transformed to another category, even if a subset of the same category, it could still be a regular functor instead of an endofunctor. For example, lets say you had a function f(x) that takes unsigned ints and returns the signed int inverse (so f(1) = -1). -1 is not part of the unsigned category since it is below the Initial value of an unsigned number (0). I'm a total newbie to category theory so I'm not sure if he's wrong or I'm missing a key detail here.
- contravariant 4y agoYou could probably try to talk about functors between subcategories by using classes, though I think there's no way to define a functor from one class to another in Haskell. Slightly more annoying is the fact that Haskell has no real product types and instead does more currying than an Indian takeaway. This makes various constructions in Category theory a bit more annoying than they need to be. If you ever wondered what on earth Applicable is and why you need it to fmap a function with multiple arguments, this is why. There's also the fact that Haskell doesn't really enforce the functor laws, nor does it give any way to really state them. Basically it uses Category theory as a close enough approximation for what it does, but various finer details get lost in translation.
- runevault 4y agoOkay this gives me something to go on, thanks!
- Y_Y 4y agoHaskell isn't the functor police! It's on you to define good functors, proving them so would be a totally different endeavour and far more difficult. I would like to understand better the issue with product types though. What do you want to do that you can't currently. By the way, most of my knowledge about the connection between Haskell and Category Theory comes from here: https://bartoszmilewski.com/2014/10/28/category-theory-for-programmers-the-preface/ https://bartoszmilewski.com/2014/10/28/category-theory-for-p...
- gowld 4y agoWhat is an example of category-theory functor in Haskell, that isn't just an endofunctor? A functor F from C to D is a mapping that associates each object X in C to an object F(X) in D. In Haskell, C and D are both the same (Hask types), hence endofunctor (functor into self). In general a functor could be something like `prime_factorizaton:: Int -> [(Prime Int, Mulitplicity Int)]`, with morphisms being things like the operation a => square :: a -> a square (n::Integer) = n^2 square (factorization::[(Prime Int, Mulitplicity Int)]) = map (\(a,b) -> (a, 2*b))) prime_factorizaton (square) x === square (prime_factorization(x))
- Iceland_jack 4y agoEither a :: Type -> Type is a Haskell Functor (endofunctor), mapping (->) to (->). Either :: Type -> (Type -> Type) is not an endofunctor, it maps a type to a type constructor and thus maps (->) to (~>) (natural transformations). If you uncurried Either, you would also get a non-endofunctor which maps from (-×>) (product category) to (->). Either' :: (Type, Type) -> Type Every function is a functor between equality, since equality satisfies congruence: isPrime :: Integer -> Bool is a functor between (:~:) @Integer an (:~:) @Bool. Boolean negation is a function between "less than or equal" to "greater than or equal" categories; mapping (<=) to (>=): not :: Bool -> Bool
- dwohnitmok 4y agoI believe the heart of what you're asking is "why do we distinguish between codomain and range?" and relatedly why do we even need the concept of "surjectivity?" For example, the function f(x) = x + x could be thought of a non-surjective "endo-"function (endomorphism) `N -> N` (where N is the natural numbers) or it could be thought of as a surjective function from `N -> E` (where E is the even natural numbers). Why do we need the "looser" version of `N -> N` when we can do with the tighter bound `N -> E`? As with many definitional things in pure mathematics, the answer is "there's no absolute iron-clad reason why you can't think of things that way, but there are a variety of reasons both mechanistic and motivated by intuition why you might not want to do that." To motivate it via intuition, let me start with another example. Take the function that maps every natural number k to the function f(x) = x + k (so it's a function whose codomain is `(N -> N)` or also expressed as `N^N`, allowing again for the fact that N^N is again "too loose" since we only care about functions of the form f(x) = x + k). Now someone could come along and say "well, f(x) = x + k" can be simply identified with just k so really the function we have is the identity function on `N -> N`, but I think most people would object and say that `k` is not the same thing as `f(x) = x + k`. The former can be thought of as an encoding of the latter, but it's not the same thing. So saying that the codomain of our function is N^N is in some sense more accurate than N and instead we can say that there's a way of embedding a subset of N^N into N via encoding f(x) = x + k as just k. The crucial thing here is that deciding whether we are dealing with an artificial encoding of something, or the real thing itself is what lets us distinguish between saying that the function's codomain is N vs N^N, and in some sense the former feels "wrong" even though it's a "tighter bound." Let's develop that intuition a little bit further. Imagine you have a function that takes a rational number and maps it to the largest integer smaller than it (that is the floor function). You could think of this function in one of at least four ways: 1. Q -> Q: A function that maps a rational number back to a rational number 2. Q -> Z: A function that maps a rational number to an integer 3. Z -> Z: Because rational numbers are countable, every rational number is "just" the indexed form of an integer, so "really" what we have is a function from Z -> Z 4. N -> N: Well by the same logic, every function on integers is just a function on natural numbers! I think the last two probably feel the most "unnatural" for folks, and most representative of the problem of "representation vs what an object 'really' is" I talked about earlier. But the first two have what is basically the same choice, just in a context where the answer isn't as clear. Do you think the integer 2 really is just the same number as the rational number "2 / 1?" Or do you think that they are different from each other and an encoding process is necessary to move from one to the other? In some cases it's useful to say "yes every integer is exactly a rational number" and in that case we can say that Q -> Q reflects this intuition best. In other cases it might be more useful to say "no an integer is not a rational number, but there is a canonical way of identifying every integer with a certain rational number" and in that case we can say that Q -> Z reflects that intuition. So your choice of codomain reflects what you think an object "really is" as opposed to just being an encoding. In this case we say that choosing Hask as the codomain (or "target") of our functor, hence making it an endofunctor, is a choice that reflects an intuition that the result of mapping using a Haskell functor is really just another type, not some other object that can be thought of as a type. From this intuition there flows a variety of practical, mechanistic ramifications. Almost always when talking about mappings we are concerned about how they affect the structure of the source and target. When we say the codomain is the same as the domain, we also almost always mean that structurally they are the same and this considerably simplifies the analysis we need to do later, because we can reuse a lot of the same machinery in the domain and codomain. If you say that the codomain and domain are not the same, then all of a sudden you have to concern yourself with the structure of the codomain and domain and prove that all the equivalences and isomorphisms you want to hold and preserve the properties you care about do actually exist and do actually preserve everything you want preserved and it's just a lot more annoying. So at a mechanistic level, what we gain from saying that "Haskell functors are only endofunctors because everything is Hask" is that we know we never map into something that has more structure than Hask; it always has the same structure. So we don't have to concern ourselves with a bunch of exploration into what happens if we map into a category with more structure than Hask.
- almostdeadguy 4y ago> If you are looking to learn the language, I recommend Learn You A Haskell. I definitely don't recommend this. While cute, Learn You A Haskell is lacking a lot of pragmatic advice about how to write software in haskell. It's good for getting you up to the FAM trio of type classes but leaves out a lot of practical advice around things like navigating base (what to use and ditch from it), the available community libraries, topics like monad transformers, and pragmatic advice around things like error handling, testing, and isolating effects from tests that come up very quickly in real world Haskell development. Haskell Programming From First Principles is a much better book IMO: https://haskellbook.com/ https://haskellbook.com/ I haven't written Haskell in a while, but there may be even better books today as well.
- eru 4y agoI mostly agree with your recommendation against Learn You A Haskell. However I would suggest people have a look at https://en.wikibooks.org/wiki/Haskell https://en.wikibooks.org/wiki/Haskell 'Haskell Programming From First Principles' is a bit too fan-boyish.
- lopatin 4y agoI thought fanboyism was one of the first principles.
- eru 4y agoWell, you'd want enlightened fanboyism.
- marcosdumay 4y agoThe only language I've seen where developers are less fanboys of it than Haskell is C++. Try asking one what is wrong with the language.
- IshKebab 4y agoHaskell feels like a language that's full of great ideas but overall nobody really likes it. Maybe it just needs to simmer for 30 years until someone comes up with whatever Haskell's equivalent of C++'s Rust is.
- schoen 4y agoFrom my late-beginner Coq student perspective, I'm amused to think that the loop detection in Haskell (which allows you to distinguish divergence from a specific instance of a type) might have made Haskell less sound from a type theory perspective, because it is in some way intervening in the calculation to add or detect distinctions that would otherwise not be a part of the underlying theory! Well, maybe that's not the best way to put it: but the example of using the <<loop>> detection to distinguish a loop from a concrete instance is something that Haskell added presumably for users' convenience; if it didn't have that feature, you would not, in fact, be able to distinguish the infinite loop from a specific value in finite time, except by manually examining the implementation!
- agentultra 4y agoAnd you definitely don't need to learn category theory or know anything about it to start writing programs in Haskell or to maintain and build large Haskell applications. A lot of category theory is fun to learn and knowing it will help you in many ways but it is not a necessary requirement. I mention this because a lot of people seem to think it is. Definitely a nice article for the math-oriented/curious/etc! It's neat seeing what Haskell isn't in order to understand better what it is.
- BoiledCabbage 4y ago> A lot of category theory is fun to learn and knowing it will help you in many ways I agree with your statement except that part. W.r.t coding, learning functional programing will help you in many ways. Learning category theory will just allow you to say "ah I've seen that concept before" - but it won't really help much.
- epgui 4y agoThe number of times I’ve heard someone say that some academic topic was not helpful and they were right is close to zero. It’s a pretty good heuristic to not adopt that attitude.
- bcrosby95 4y agoThis statement reads as really weird. You seem to be saying that your opinion and/or experience on the usefulness of academic topics is a good heuristic to use to not adopt an attitude.
- pizza 4y agoMakes sense to me. People often attribute uselessness to that which their imagination struggles to engage. Note that OP didn’t say: “everything everyone else says is useless is useful” but rather “rushing to judge something useless is a very noisy predictor of actual uselessness”
- 4y ago
- markusde 4y agoIMO after the first section the headings in the post are misleading: - A functor is "not a functor" because not all endofunctors on Hask can be written as Haskell Functors. - A monad is "not a monad" because you can implement a monad without satisfying all the monad laws. I don't think either of these statements _really_ evidence the claims the headings make. Good post though, I always find that it's useful to think about the subtleties between mathematical objects and their implementation.
- hackandthink 4y agoAndrej Bauer wrote a popular post in 2016 (Hask is not a category): https://math.andrej.com/2016/08/06/hask-is-not-a-category/ https://math.andrej.com/2016/08/06/hask-is-not-a-category/ Mathematicians are still thinking about this stuff. A recent post by Mike Shulman, asking about Agda (Haskell for mathematicians): https://proofassistants.stackexchange.com/questions/1887/categorical-semantics-of-agda https://proofassistants.stackexchange.com/questions/1887/cat...
- dan-robertson 4y agoHaskell is a pretty fun language to learn and if you’re interested in trying to translate concepts from category theory into programming, it’s probably a good language to use. Haskell is not category theory in the same sense that arithmetic is not group theory: there’s only really one category. Well sort-of because type constructors let you work in different subcategories. Category theory is about different categories and the nature of the relationships between them. It usually operates at a level of ‘let C be a category…’ with concrete categories or functors being examples. Haskell operates at a level even more concrete than single objects in a single category: the objects are types and Haskell operates on the values of those types. Of course Haskell can work at slightly higher levels too, but it never really escapes categories that look a lot like Hask. Maybe that statement is too strong though. I’d be keen to see some interesting actual-category-theory level things in Haskell. (Maybe I’m being unfair and these do exist but I am considering them to not count as ‘actual category theory’) I thought that the ‘categorical theory of patches’ thing was a good example of category theory applied to programming but note that it didn’t require any kind of general notion of e.g. push-outs in a programming language.
- valcron1000 4y agoThis post is literally the "Ackchyually" meme. There is a reason why "fast and loose reasoning is morally correct".
- agalunar 4y agoI might be a counterexample to the claim that "this is pedantic and the differences they're mentioning are meaningless in practice". I learned about functors in uni and only later took a look at Haskell. I was genuinely very confused by the naming of Functor: functors map both morphisms and elements, but this isn't the case in Haskell. So I was left wondering whether I had missed something.
- smackmybishop 4y agoThey actually do. The type constructor maps types to types (which are Hask objects), and `fmap` maps the functions (which are the morphisms).
- agalunar 4y agoah, sorry! right – the type constructor and fmap together make up a functor. I meant functors where the objects being mapped aren't types, but type inhabitants, and the morphisms being mapped are not arrows between types, but arrows between type inhabitants. (I suppose this also has to do with "the only category in Haskell is Hask", rather than types also being themselves categories?)
- pema99 4y agoI do actually agree with you. The goal for me was just to understand the connection to CT a bit more precisely, not to imply that it isn't useful. I guess I didn't convey that part very clearly, which together with the tongue-in-cheek title might make me sound like quite a pedant. The post is the culmination of me already knowing Haskell, googling category theory one day, and being utterly confused.
- luuuzeta 4y agoWhat caught me off guard was the "(uwu)".
- justinhj 4y agoEnjoyed the article as a functional programmer and category theory enthusiast. Haskell does not have to be a strict encoding of Category for it to be useful. We are grown ups and can understand that not everything is perfect and we can overlook some warts in order to benefit from a beautiful set of rules that help us think about composition as a first class citizen in our work. The first thing mathematicians tell you when talking about categories of, say, sets, we have to do some hand waving to avoid Russel's Paradox. In other words even mathematicians have caveats when talking about different aspects of category theory. In the case of the Functor, we use fmap and not a "function that lifts functions" because it is much more ergonomic. Yet, it is just as "correct" since it is isomorphic to lifting a function and applying it. With monads we use bind and flatmap although the most obvious categorical implementation would be a simple compose function. That maps more directly to the "category of endofunctors", but again it is isomorphic to the same code that uses flatMap/bind, and the same laws hold. A lot of utility has been gotten from analogies with category theory and as long as we hold our noses we can ignore the occasional whiff of in-authenticity. I don't believe that you need to learn category theory to take advantage of the concepts we have borrowed, but it does make everything become more coherent to dig into it a little. It's also a lot of fun if you like that sort of thing.
- xwowsersx 4y ago> I recommend Learn You A Haskell. LYAH is a fun read, but for someone trying to learn the language seriously — by this I just mean more than a casual tour to get an idea of what the language looks and feels like — there are, thankfully, some much better resources and books available these days. No shade to LYAH intended whatsoever, but it's just not what I'd recommend for some undertaking really learning the language. https://haskellbook.com/ https://haskellbook.com/ is a solid option IMO.
- eBombzor 4y agoWhat are the prereqs for learning category theory? I looked up a definition online and it had a lot of stuff I've never heard before. What exactly is a mapping in this context
- deleted 4y ago[deleted]