10 ms·
Haskell People
- quickthrower2 9y agoNice post. A monoid is an interesting and underrated "pattern" for objects where you can have a "nothing" and an operator that smashes two values together. The operator may be 'lossy' as in 3 + 4 = 7, or it might preserve the originals to some extent as in "3" + "4" = "34". I realized the power of this when working with a new library and thinking "how do I concatenate these", all I had to do was check that the data was a Monoid and used mappend. There is something very satisfying about that. Plus if you build some utilities on monoids, they'll work with lots of distinct objects, from parsers to numbers to lists to all sorts of other things. What Haskell lacks in the community is people blogging about how to get more mundane things done like setting up a CRUD website, API, or desktop app. I have a site in my profile that attempts to fill that gap.
- diminish 9y ago>> algebraic structure I talk about the most passionately is the monoid Can you ELI5 monoid? what problem does it solve which isn't easy in other languages without it? edit: thx everyone.
- PieSquared 9y ago"Monoid" is an adjective that describes a data type. Anything you describe as a monoid has to have three properties: you can add them together, there's an "empty" or "zero" value, and (a + b) + c = a + (b + c). For example, strings with concatenation are a monoid, because you can use an empty string and the string + operator. For example, integers with addition are a monoid, because you can use 0 and the integer + operator. For example, sets are a monoid, because you can use the empty set and the union operator. For example, a "Picture" data type could be a monoid, because you could have a fully-transparent picture and use an "overlay" operator to put one picture on top of another. Why do you care? Well, for one thing, it just makes it easy to find the function or operator you want to use: as the OP said, if I feel like my data type should have a concat or append operator but I don't know what it's called, I just use mappend / mempty / mconcat. But, as another practical example: "sum" in Python works for numbers, but I've seen folks assume that it works for anything that you can use + on, and so try and use strings with it. But, because "sum" isn't a general purpose tool, that doesn't work! In Haskell, on the other hand, the equivalent -- mconcat -- will work on anything that is a monoid. (And can be specialized to work faster for specific data structures.) Other languages also have monoids. If someone tells you Haskell has monoids and other languages don't, what they really mean is, Haskell makes explicit the monoid pattern / interface, where other languages have it implicitly for different data types. Talking about the pattern explicitly isn't revolutionary, but it can be pretty useful for discoverability and writing "general" algorithms. Instead of calling data structures monoids, you'd get the same effect if, as a programming language community, you decided that as many types as possible should support "+", and that every data type that can should have a makeEmptyThing() method, and that it would be weird and not ok if x + makeEmptyThing() didn't equal x and if (x + y) + z didn't equal x + (y + z), and then subtly shamed any libraries that defined makeEmptyThing() and + in ways that didn't follow that pattern. But if your programming language community did this (for consistency) you'd probably want to come up with a name for it -- "Addable", "Concatable", etc -- and the Haskell community chose "Monoid" (because of relationships to theory etc etc).
- dllthomas 9y agoI agree with much of what you say here. Some refinements and small disagreements follow: A monoid isn't just a data type. Mathematically, it's a set ("data type" is plenty close enough, in this context) and an operation. Integers with addition are a monoid. But so are integers with multiplication. And these are two different monoids. Haskell confuses this issue a bit - they way the Haskell libraries are set up you can only name one Monoid instance per type, and so types that form monoids in several interesting ways get wrapped in "new types" so you can name each of the several. This mostly works fine, but is a bit hacky from a math POV, and I think doesn't lead as well as it might to a more general understanding. It's worth noting, too, that some of the Haskell libraries - particularly those from the early days - make some unfortunate decisions about what instances to bless. I often complain about the Monoid instance for Map. Map forms a monoid under union so long as we combine values (on collision) associatively. Unfortunately, the library doesn't let us pick how they are combined, it just takes the left one. That's usually not what I want, and it's particularly painful when I've been combining Sets with monoid operations and now realize they need to carry some extra info. ... and then of course there's floating point, which probably shouldn't even be Num. > But if your programming language community did this (for consistency) you'd probably want to come up with a name for it -- "Addable", "Concatable", etc -- and the Haskell community chose "Monoid" (because of relationships to theory etc etc). There are two things I really like about using the name Monoid, compared to the others. First, it's much clearer what the rules are. We aren't stuck wondering whether strings or products are "really" "Addable", whether functions of the form (a -> a) are "really" "Concatable" (... and what about nonempty strings? you can concatenate them, but they have no identity object...). Clarity in an interface means I know what properties I can rely on. You can define those properties precisely with "more intuitive" names, but then the actual interface doesn't match the intuition and people won't realize it, which is worse. You could get precise and intuitive by adding verbosity - "AssociativeOperationWithIdentity". My principle objection there is readability and aesthetics, but if that's what a community wants to go with okay... "Monoid" is short and unambiguous and well established in related fields. That last point touches on the other thing I like. There are mathematical results that can be useful to programmers. Reducing the translation needed helps make those more accessible. And everyone could do with knowing just a bit more algebra :-P
- 9y ago
- danidiaz 9y agoA monoid is an interface with two operations: one that produces an element out of thin air, and one that combines two elements. It also comes with a contract, like the contracts of "equals", "hashCode" or Comparable in Java. The contract says that the operation must be associative, and that the element you produce out of thin air must be neutral: when you combine it with another element it leaves the other element unchanged. One benefit of having such general interfaces is that you can reuse code across a wide range of domains. For example: the Comparator interface in Java can be seen as a monoid, with the "thenComparing" function as the combination operation: https://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html#thenComparing-java.util.Comparator- https://docs.oracle.com/javase/8/docs/api/java/util/Comparat... You could build a list of comparators and concatenate it, map a function that produces a comparator over a list and concatenate it, and so on. Another benefit is that you can be quite general when specifying requirements for your functions. In Haskell, the Writer monad only requires the type of the accumulator to be an instance of Monoid. So you can user regular lists, difference lists, or the integers under addition. Also in Haskell some composite types automatically satisfy an interface if their components do, saving you work. For example, a tuple of monoids is automatically a monoid. Any function that returns a monoid is itself a monoid as well. (Functions that begin and end in the same type can be monoids in a different way: the neutral element is the identity function and the combination operation is composition.)
- kreetx 9y agoMonoid is a type class, similar to interfaces in Java, and this is what it makes easy: if your code uses the monoid interface of some type then you can swap the underlying concrete type without changing your code, and it still works. Obviously, you can do that in any untyped language, too, but explicitly defining these contracts makes code easy to manage and understand. And the compiler will tell you if/how you're doing something wrong.
- mightybyte 9y agoA monoid is something that allows you to take two of the same kind of thing and smash them together to be one of that same kind of thing. It also requires you to have an "empty" thing that can be smashed together with any other thing without changing the result. In code: smash :: Monoid a => a -> a -> a empty :: Monoid a => a A monoid is a property of things, not languages, so the idea of "a language without a monoid" doesn't really make sense.
- deleted 9y ago[deleted]
- catnaroek 9y agoAh, so this is a monoid: instance Monoid Int where smash 25 x = x smash x 25 = x smash x y = 2*x^2 - 3*x*y empty = 25 Thanks for explaining!
- amelius 9y agoI think combining 25 and x should yield x.
- catnaroek 9y agoOops, yes, my bad.
- deleted 9y ago[deleted]
- mjhoy 9y agoThere are also the monoid "laws" (not checked in Haskell): empty `smash` x = x -- left identity x `smash` empty = x -- right identity (x `smash` y) `smash` z = x `smash` (y `smash` z) -- associativity Your definition doesn't fit any of these. (Edit: you've rewritten to meet the first two; but it is not associative.)
- conistonwater 9y ago
- dmitriid 9y agoThe irony is that there are now 4 monoid tutorials in the replies, and they are all different, and differently confusing :) And there I was, thinking that this only applied to monads :)
- throwanem 9y agoPerhaps someone should come up with a generalizable method for combining monoid tutorials. I wonder what we could call it...
- kahnpro 9y agoIs it really so confusing? I mean, if you understand + for integers and for strings and for lists, and you can understand why this is basically the same operation for all of them, congratulations! you know what a monoid is.
- dmitriid 9y agoIt's not confusing to me :) I'm just saying that at the time I wrote my comment there where four different comments with four different ways of explaining monoids with four different sets of terminology :)
- sillysaurus3 9y agoA monoid is a method of converting coffee into internet comments about monoids. It's quite ingenious, really.
- ostochast 9y agoFor some people it is easier to understand a concept, especialy an abstract one, if they are given a few examples. For those people: A monoid is a set and an binary operation on the elements of that set with the following properties: 1.The operation acts on two elements of the set to produce another elemenent of that set(closure). Examples: You have a set od natural numbers {0,1,2,3..} with standard addition. Whichever two natural numbers you choose to add you will get a natural number back. A set of MxN matrices and matrix addition. If A and B are two MxN matrices A+B is a MxN matrix. 2.The order in which the operations are performed does not matter(associativity). So for all elements of our set a,b and c and the operation +: a+(b+c)=(a+b)+c must be valid. Examples: Let L be a set of strings and + concatenation. "Just"+(" an "+ "example")=("Just"+" an ")+"example" Vector addition over vectors of same dimension. 3.There is an element(unique!) in the set which when applied to any element of the set returns that element(identity, neutral element). e+a=a+e=a e is identity Examples: 0 is identity for standard addition: 0+1=1, 4+0=4 1 is identity for standard multplication: 1*7=7 ""(empty string) is identity for string concatenation
- egl2019 9y ago"Yet another monoid tutorial." This time in Hacker News comments. And lots of them. :-)
- nine_k 9y agoCan't help but quote: "I see poorly implemented monads everywhere. They don't even know they're monads." Indeed, being acquainted with Haskell makes you write and see code in other languages differently, see different and more important patterns than "visitor" or "factory", and use their properties.
- dustingetz 9y agowho said that?
- nine_k 9y agoCan't remember; I saw at as a meme, with the boy from Sixth Sense as the template.
- resu_nimda 9y agomore mundane things Even the most reasonable of "Haskell people," the OP included, seem to have this built in condescension for programs that actually do things. Still waiting for the Haskell community to produce something non-mundane to justify all that. If there was just one example of something that clearly demonstrated the unique value of Haskell to non-category-theory-enthusiasts.
- paultopia 9y agoPandoc? I've never looked into the code (because haskell might be even harder to read than to write), but it's the obvious example of something super useful that was written in Haskell...
- nh2 9y agoWhere do you get that from? There are lots of practical Haskell projects that "do things": From web frameworks over window managers to cryptocurrencies, and also many commercial projects that are all but mundane and where nobody cares about category theory. You can also check out https://haskell-lang.org/libraries https://haskell-lang.org/libraries for some pretty practical documentation on libraries that Haskell programmers use to build programs that "do things".
- wrs 9y agoOf course Haskell programs do things...lots of things. Are you sure you're not being condescending to people who want their programs that do things to have a solid mathematical foundation as well?
- matt_kantor 9y agoHere are a few examples: - http://store.steampowered.com/app/458200/Rumpus/ http://store.steampowered.com/app/458200/Rumpus/ - https://postgrest.com/en/v4.3/ https://postgrest.com/en/v4.3/ - http://skedge.me/ http://skedge.me/ - http://darcs.net/ http://darcs.net/ - https://pandoc.org/ https://pandoc.org/ - https://git-annex.branchable.com/ https://git-annex.branchable.com/ Some lists with more: - https://wiki.haskell.org/Haskell_in_industry https://wiki.haskell.org/Haskell_in_industry - https://wiki.haskell.org/Haskell_in_practice https://wiki.haskell.org/Haskell_in_practice Also, a bunch of programming languages are implemented in Haskell.
- aaron-lebo 9y agoThere's probably some truth to this. My mathy friends have a deep appreciation of Haskell. I always try to get into it for a few weeks, marvel at it, grok some new things, then inevitably end up in more "practical" languages (only because there are almost no domains, save parsers and compilers, where Haskell is obviously the "best" fit). This may describe why: Haskell it built for the sake of itself, it's coherence, it's design. It is first and foremost designed to do things the Haskell way, which may be conceptually pure and "right" but aren't necessarily the most straightforward. In contrast, most other languages exist to solve a problem C++ (performance and control), PHP (a templating language for the web), Python (web, data science), JS (browser), etc. This being my understanding/paraphrasing of what the author is saying. I think the answer is somewhere in the middle: the good parts of Haskell, selected for pragmatism (strict instead lazy like most languages), with an emphasis on being approachable to users. There's a lot of languages that are almost there. Elm gets the ease of use but strips too many features. OCaml is practical but has std lib split, multicore issues, and is kind of crufty. Go is arguably too simple, Rust is too low-level, Kotlin is almost there but the JVM can't replace languages that can produce straight binaries for the most part. Nim is very easy to write in a functional style and is maybe the most practical language I've ever used. It lacks the support, libraries, and mindshare of the others, though. What kind of worries me is there is a strong incentive for languages to promulgate themselves into domains they aren't especially suited for, so it's more likely that one of these flawed languages will be Frankensteined into a domain it doesn't really belong and we'll be hacking around those disadvantages in a couple decades. Maybe the real answer is to take a step back and consider what is a middle ground that gets 90-95% of what anybody needs. I'm not convinced that something like Nim or a new language couldn't be 99%, with the 1% of the time being necessary to drop into domain specific languages. If one of the big corps put support and funding into the "right" language, it's not really a difficult job, but it is those damn incentives. How do you fix them?
- kobeya 9y agoActually the same could be said about Python and the Python way, pythonic programs, etc.
- 9y ago
- dmitriid 9y agoThis entire post is so true. As a personal (not so personal anecdote). Purescript[1] Book[2] claims "No prior knowledge of functional programming is required, but it certainly won’t hurt. New ideas will be accompanied by practical examples, so you should be able to form an intuition for the concepts from functional programming that we will use." And then it goes through a rather gentle introduction of various concepts. And then this is the first time ever that `map` is mentioned: > Fortunately, the Prelude module provides a way to do this. The map operator can be used to lift a function over an appropriate type constructor like Maybe (we’ll see more on this function, and others like it, later in the book, when we talk about functors) WTF. "lifting over typeclasses wat". The whole concept of lifting isn't discussed until six chapters later. [1] A Haskell-derived/Haskell-based language that compiles to Javascript, http://www.purescript.org http://www.purescript.org [2] https://leanpub.com/purescript/read https://leanpub.com/purescript/read
- zengid 9y agoThe podcast that she links too is really interesting [1]. Talking about what its like to learn Haskell as a first language. Really interesting for me because I'm getting into Elm, and their approach is to use really concrete ideas and names instead of Monads and such. She even mentions that Elm is a good way to start approaching Haskell concepts (around 13 minutes). [1] https://twitter.com/thefrontside/status/912327851386470400 https://twitter.com/thefrontside/status/912327851386470400
- sidlls 9y agoThe content of the article makes it abundantly clear the author isn't talking about "understand thing," but rather specifically "understand Haskell." These aren't identical.
- tclancy 9y agoI don't see that at all. To me it was clearly about how using a language that is designed to be correct rather than useful/ simple places more responsibility on the coder to think about the entirety of their problem before digging in.
- sidlls 9y agoWe can agree to disagree. I see no evidence to support your generalization in the article. It's also a contentious assertion besides, since the implication is that people who don't use "correct rather than useful/simple" language don't "think about the entirety of their problem before digging in."
- runeks 9y agoI’ve encountered multiple times that Haskell has forced me understand exactly what I was doing, otherwise the parts wouldn’t fit together, or I’d end up writing huge amounts of duplicate code. I’ve never encountered this in another language.
- hellofunk 9y agoI like Haskell a lot, but it has one aspect that has only bothered me. A lot of incidental complexity is added due to the prevalence of custom functions/operators with arbitrary associativity and fixity, on top of normal precedence rules. Perhaps it is because I got spoiled by writing lisp (Clojure) where such concerns never exist in such a uniform language. But writing Haskell can lead you to make lines of code that don't always read in the order you'd expect. I was always having to lookup the fixity and associativity of things to know what was going on just in a single otherwise straightforward line of code.
- kmicklas 9y agoAgreed. Though this is really a problem with text based editing (which obscures the tree structure), not Haskell.
- chris_st 9y agoI remember hearing this said about Lisp programming in the early 1980's. Specifically, there was a "tree-based" editor for InterLisp on the Xerox Lisp machines... I only ever met one person (hi Marty!) who even basically understood it. I really hate the "we've never had one so we'll never have one" argument about anything, but I think in this case it may well be true, although the argument stems from the fact that a lot of people have tried to make "tree based" editors, but I've never heard of anyone making one that got any kind of traction. Even the guy who could use the Xerox tree editor preferred emacs (on other machines).
- kmicklas 9y agoThe problem with tree editors has always been the lack of standardization, not any kind of conceptual or UI problem. Generally authors take one of two roots: 1) Provide a tree based editing UI layer on top of text files since text still rules. In my opinion this is almost like the worst of both worlds, though it can be successful. Paredit is probably the best example of this (and many lispers swear by it). 2) Create a Grand Integrated Vision of How to Fix Every Programming Problem Ever Created. This can make a nice demo, but of course never turns into a practical product any time soon. Until we have a standardized tree or graph interchange format that is designed to satisfy the common denominator of the full range of languages, protocols, etc., as text does today, all structured editors will be fighting an uphill battle.
- Tade0 9y agoInteresting title. In my experience, Haskell is for Haskellers more than just a language. I have found that every Haskeller I talk to is, in the specified order: 1. A Haskeller. 2. A programmer. 3. A human being. 4. A person of a specific gender. They really are "Haskell People". What's even more bizarre is that for some other languages this hierarchy seems to be reversed. That being said I'm glad that the word "sucks" was finally removed from this article: https://wiki.haskell.org/The_JavaScript_Problem https://wiki.haskell.org/The_JavaScript_Problem
- Roboprog 9y agoThanks for the article link. I love that "late binding" is listed as a flaw. Some would call that a feature. Those of us in the "some" must be wired a bit differently that the "early binding" crowd, I guess :-)
- Roboprog 9y agoDisclosure: using JS for UI work, not nuclear reactor controls. Hate reading reams of verbose, flabby, painfully explicit, long, statically typed (often believed to be "self documenting", as well), code. Prefer short, intuitive code (and LESS of it, but with explanations of context and "why") for non safety critical work.
- chongli 9y agoHaskell is one of the least verbose languages out there, typed or otherwise.
- matt_kantor 9y agoHaskell's syntax is very terse, but Haskell codebases can still be more verbose than JavaScript ones because the type system actually makes you think about things like error states. JavaScript is definitely more verbose when you write code for all paths and not just the happy one, but doing so seems far less common in practice than it ought to be. Another angle on the parent comment is that Roboprog hasn't been exposed to statically-typed languages with good inference. It sounds like they're mostly complaining about type annotations, but at least in Haskell you can get quite far without having to annotate anything.
- georgewsinger 9y agoThe experiment to bring "Haskell people" into the world of VR has so far gone well (https://github.com/SimulaVR/Simula https://github.com/SimulaVR/Simula), but I have sometimes wondered if Haskell is too off-putting of a language to bring traditional graphics programmers into this project.