7 ms·
I kind of like Haskell, but the learning curve is brutal and the documentation is often intensely non-helpful if you don't want to learn a whole lot of mathemat
by phs2501 10y ago
I kind of like Haskell, but the learning curve is brutal and the documentation is often intensely non-helpful if you don't want to learn a whole lot of mathematical terms.
i.e. when browsing and trying to understand parts of the XMonad code, I came across the "Endo" type. I Hoogle'd it, and the only documentation for it is "newtype Endo a: The monoid of endomorphisms under composition." Thats.... not helpful for me.
- evincarofautumn 10y agoThe biggest thing missing from Haskell docs is examples, I find. The mathematical language is tempting when you’re writing docs, because it’s succinct and precise, and can say a lot about how something’s implemented: -- Endo is… newtype Endo a = Endo { appEndo :: a -> a } -- ^ -- | -- …the monoid of endomorphisms… -- | -- V instance Monoid (Endo a) where mappend (Endo f) (Endo g) = Endo (f . g) -- ^ -- | -- …under composition. mempty = Endo id But not so much about how to actually use it: -- If you’ve got a list of functions… pipeline :: [Int -> Int] pipeline = [(+ 3), (* 2), abs] -- …you can compose them with the generic mconcat. run :: [a -> a] -> a -> a run = appEndo . mconcat . map Endo run pipeline (-1) == 5
- stcredzero 10y agoNone of that helped me understand anything.
- catnaroek 10y ago“Endo” is a type constructor for functions that have the same domain and codomain, so if you have two values of type “Endo Foo”, for any type “Foo”, you know that they can be composed in either order. That composition of such functions is associative and has an identity, I hope it isn't necessary to explain.
- walkingolof 10y agoI think you got the Haskell issue right there.
- catnaroek 10y agoMathematical functions are taught in school. That function composition is associative and every set has an identity function, this is stuff that every high school graduate should know. --- Reply to montatonic here: I'm neither a Haskeller nor do I want to see Haskell “take over” the world. Some of my comments even got lots of downvotes from Haskellers. --- Reply to sidlls here: Yes, FWIW, I don't really agree with the use of the term “endomorphism”. It isn't even precise: the type `Endo` is inhabited by endomorphisms is one specific category (Hask), not endomorphisms in arbitrary categories. So “endofunction” would be both more accurate and less pompous. As for “codomain”, I can't agree, though. This is really high school stuff.
- montanonic 10y agoHow to take over the world as a programming language community: Neophyte: Hello, I do not understand this. Haskeller: You should already know this.
- dllthomas 10y agoThat's been very far from my experience, when learning Haskell or teaching it. And as mentioned in the comment, the parent poster is not "a Haskeller".
- sidlls 10y agoThe jargon "monomorphism", "codomain", "endomorphism" and even "function" and "domain" as it truly applies here are most certainly not taught even as part of a typical high-school calculus program. I can't speak for IB (they only offered AP when I was in high school, so long ago). The basic, hand-wavy version ("a function maps a domain to a range") is about as complicated and deep as it gets.
- openfuture 10y agoThat just means you are missing some foundation. If you are interested in understanding the theory I really recommend this: https://www.youtube.com/watch?v=I8LbkfSSR58 https://www.youtube.com/watch?v=I8LbkfSSR58 https://bartoszmilewski.com/2014/10/28/category-theory-for-programmers-the-preface/ https://bartoszmilewski.com/2014/10/28/category-theory-for-p...
- codygman 10y agoMost people don't Immediately go to learning foundations like that without having an idea of what they'll get out of it first, is the problem. For example, the poster you replied to can only see the advantage being that his question is answered. The tangible benefit for taking time out of the day to go and read those foundations needs to be made more clear I think.
- yawaramin 10y agoOK, the basic idea is that you have two functions, `f_1` and `f_2`, of type `a -> a`, and you want to run them both on an input value `x` to get an output `y`. You can think of `f_1` and `f_2` as a data pipeline that `x` passes through and then the output comes out the other end. So, y1 = f_1 x y = f_2 y1 -- or, y = f_2 (f_1 x) But what if you have an arbitrary list of functions as your pipeline? y = f_n (f_{n-1} (... (f_2 (f_1 x)) ...)) Well, the solution is that functions of type `a -> a` are composeable, so you can 'add them up' as if they were real values (which they are). The Haskell function composition operator is `.`, so: y = f_2 (f_1 x) -- is the same as, y = (f_2 . f_1) x Now, how do you go from 'composing two functions' to 'composing a list of functions'? Well, monoids are a typeclass (a statically-enforceable design pattern) that encode the idea of being able to combine two things into one, and 'for free' give you a function `mconcat` that combines a list of those things into one. So if you have a monoid instance for functions of type `a -> a`, you're now able to combine many of them together, get a single composed function, and apply your input value `x` to that. `Endo` is just a fancy name for 'function of type `a -> a`'. I agree to a large extent that all this category theory stuff can get distracting. I personally think type theory is a much more rewarding field of study. To 'endomorphism', a type theorist would say, 'Oh, you mean `a -> a`?'
- lobster_johnson 10y agoThis is an extremely lucid answer, thank you. Can you please now rewrite all the Haskell documentation in the same way?
- jholman 10y ago+1 (I know "+1" posts are a sin, but if a few more haskellers take heed of the documentation problem, it'll be worth me getting hellbanned.)
- majewsky 10y agoThis. Documentation is the most frustrating part of the Haskell experience to me. More than once I've come across a module on Haddock and the module description just says This module is inspired by the following paper: <DOI>
- deleted 10y ago[deleted]
- deleted 10y ago[deleted]
- montanonic 10y agoAnd yet the following is profoundly more intelligible to a wide range of functional programmers: -- Using Elm syntax pipeline : List (Int -> Int) pipeline = [(\x -> x + 3), (\x -> x * 2), abs] applyPipeline : Int -> Int applyPipeline value = List.foldr (\func val -> func val) value pipeline -- or more succinctly applyPipeline_ value = List.foldr (<|) value pipeline Getting lost in the mathematical abstractions is really no help here. In niche circumstances I'm sure it's great, but like.... not here.
- willtim 10y agoYes it is a bit unnecessary in the simple list example above, but Endo becomes useful when using arbitrary nested Foldable structures and when composing monoids, e.g a pair of monoids is also a monoid. In other words, it becomes useful at scale. To quote from Paul's post: "The trouble is that very often, the sorts of examples that are easy to discuss aren’t of sufficient scale to reveal any major differences between A and B."
- evincarofautumn 10y agoI agree Endo doesn’t add a lot of value. I tend to use “compose = foldr (.) id” for this, if it’s even necessary—most of the time my “pipelines” are not dynamic, so there’s no reason to put them in a list in the first place.
- montanonic 10y agoThis brings to mind what I consider to be perhaps the biggest issue with Haskell (I'm not accusing you of this, you've done a great job explaining): due to language expressiveness, overly generic code is far too often a baseline, when it really shouldn't be. The language itself doesn't demand we write code this way, but the community, understandably, loves to be as expressive as possible in many cases. But all of this comes with a cost of cognitive overhead that seems to rarely be worth paying. Elm was an enlightening experience for me, having started with Haskell, because it helped me to realize just how little I ever took advantage of a lot of the very generic Haskell code, and how far the simplest of functions and types could take you in the overwhelming majority of cases.
- codygman 10y agoIf you aren't planning on submitting that to those docs I will. In fact I'm sure many would find you adding examples along those lines to the most popular but math inspired Haskell libraries.
- dllthomas 10y agoAs an aside, it's worth noting that we bother giving `a -> a` a name other than `a -> a` here because there are other monoids for things of similar forms and there's overlap. For instance, functions of the form `Monoid b => a -> b` can be combined by combining their output, and that gives us a different monoid with `const mempty` as the identity.
- sidlls 10y agoIt isn't helpful for anybody but a narrow slice of mathematicians and computer science graduates.
- catnaroek 10y agoI'm neither of those, and I understood it just fine. The term “endomorphism” might sound scary, but once you read the definition, which is just one sentence long, it's actually a pretty simple concept. Have fun cramming the definition of any object-oriented pattern into a single sentence. --- Reply to sidlls here: I didn't say that the term might sound scary to you. I said that the term might sound scary in general, to “average” people. Because, frankly, relative to its actual mathematical content, the term is perhaps a little bit too pompous. Also, when it comes to mathematical definitions, I wouldn't say one really knows a definition unless one can use it in a calculational setting.
- awfgylbcxhrey 10y ago(terse && correct) != helpful The art in writing documentation is in effective communication to a varied target audience, not in simply fulfilling the obligation to be technically correct.
- catnaroek 10y agoSure, I don't disagree. I've bashed my head countless times against short, super-abstract definitions for which it is very difficult to provide concrete examples. So I totally empathize with the feeling you express. However: (0) As for “endomorphism”, the definition “function with the same domain and codomain” should be pretty easy to understand to anyone. (Technically, in an arbitrary category, morphisms don't have to be functions, but Haskellers work in the category Hask, whose morphisms are terminating functions.) (1) The right place to define what a monoid is is the definition of the class Monoid, not the definition of every type that happens to have a Monoid instance.
- grey-area 10y ago