30 ms·
What Is Good About Haskell?
- lngnmn1 7y agoWhat is good about statically typed with type-classes and highly sugared lambda calculus (which surpasses even Miranda) that complies into a native code? Everything.
- nicoburns 7y agoMy Haskell isn't good enough to translate, but I'd love to see these examples in Rust. I believe Rust has all of the Haskell features mentioned in this article, but with a much more familiar syntax. The tree data type in Rust could be: enum Tree<A> { Leaf(A), Node(A, Box<Tree<A>>, Box<Tree<A>>), }
- sampo 7y agoWhy should enum Tree<A> { Leaf(A), Node(A, Box<Tree<A>>, Box<Tree<A>>), } be more "familiar" syntax than data Tree a = Leaf | Node a (Tree a) (Tree a) ?
- roar-of-time 7y agoThe syntax and terminology (enums, structs, etc.) is more familiar to C++ / C# / Java users.
- Athas 7y agoI always found the use of "enum" for things that are not really enumerable in a useful way to be very confusing. Or are Rust "enum"s enumerable in some subtle way that I don't recognise? Is it just some vestigial term that now has no relation to its original meaning? At least in C, "enum"s are enumerable because they are just integers.
- loeg 7y agoRust's "enums" look more like tagged unions to me. I guess the tag is enumerable? Although I also don't understand why Rust called tagged unions "enums."
- steveklabnik 7y agoThey enumerate a possible set of valid values. Hence “enumeration.” They are tagged unions, but sometimes, the tag doesn’t exist. Or rather, invalid parts of values can be used so that the tag isn’t an extra bit of data, but instead is built into the same space. “Tagged union” gets too deep into only-mostly-accurate implementation details to be a good name.
- loeg 7y agoThey seem to enumerate a possible set of valid structures which can hold arbitrary values. I guess it's just so different from C enums I'm having trouble understanding why the name was repurposed. It's probably less different from C++/C#/Java enums (I know at least one/some of those languages have more complicated enums than C). Sure, tagged union implies a particular implementation that may not always be required, but it's conceptually easy to understand and doesn't have the historical baggage. (Maybe a better description would be strongly typed union? I want to make clear I'm unfamiliar with Rust and just guessing based on the syntax presented.) I think the biggest problem with "tagged union" (or the even longer "strongly typed union") is that it just isn't a good keyword name — it's two (or three) words and fairly long. No one wants to type out 'tagged_union' and from that sense, 'enum' is better. I don't have a better suggestion for you, and IIRC Rust 1.0 has now frozen the language to some extent. Thanks for trying to explain, I appreciate it.
- steveklabnik 7y agoThey can be any data type; just a name, a struct, a tuple struct, or even another enum. I think also, likewise, “union” sounds strange unless you have C experience. Many of our users do not know C, and so that name doesn’t help them either. In the end names are hard. Happy to, you’re very welcome :)
- tiborsaas 7y agoI know what enum is, but data for me is just 1 and 0. Are we assigning here with the =? What does the pipe symbol mean? Why pipe instead of another =? Why the weird formatting? To me Haskell's look is too off-putting. With the Rust example I have a good guess what will the resulting object will look like. But I know it's just a learning experience. Once I would know Haskell your example looks more elegant to me. I just don't get it from looking at it :)
- thethirdone 7y agoYour questions are probably mostly rhetorical, but I'll give a brief answer to them. > Are we assigning here with the =? Kindof you are assigning what the type `Tree a` is. > What does the pipe symbol mean? The pipe is symbolizing or/either here. A tree is either a Leaf or it is a Node with two subtrees. > Why pipe instead of another =? You are building up a single type with the pipes, having an extra = wouldn't really make sense when you are thinking about building a type algebraically. > Why the weird formatting? The formatting is optional. It is free to be all in one line if you want it that way. For the given example, I would probably make it a single line, but I'm not a Haskell veteran.
- globuous 7y agoHence Eich’s famous « I was under marketing orders to make it look like Java » :)
- tiborsaas 7y agoWell, the marketing folks were right after all :)
- mrkeen 7y agoHaskell: A Tree ="IS" a Leaf |"OR" a Node In the Rust syntax ',' means both OR and AND. A Tree {"IS" a Leaf ,"OR" a Node A Node ("IS" an A ,"AND" a Box ,"AND" a Box.
- the_af 7y agoThe formatting is no weirder than Python's. You could ask many of the same questions of Python's non-C/non-Java like syntax: - What is "def"? - Why the weird formatting? (And unlike Haskell, Python's tends to be stricter!) - Why do I need to write ":" after some lines but not others? It doesn't work like the semicolon in C-like languages! - What's with the "if __name__ == '__main__'" weirdness I see in some Python programs? - What's this weird [f(x) for x in ...] syntax? It doesn't look like anything in C. What's with the brackets anyway? Etc. Yet Python with its "weird" syntax and constructs is a hugely popular language...
- HorstG 7y agoThere is a huge unreadability right there staring at me: What does that Box<> do, and why? Rust is borrowing more and more of the obscurities of C++, and thats not a good thing...
- Munksgaard 7y agoBox puts something on the heap and returns a pointer to that thing. Here it is necessary because otherwise the Rust compile wouldn't be able to determine the size (in memory) of a Tree.
- SamReidHughes 7y agoBox<T> is a type, so it’s confusing to say it returns a pointer. It holds a pointer. GP should note that C++’s unique_ptr isn’t an obscurity.
- HorstG 7y agoCalling it Box is confusing. unique_ptr would be an improvement for the name, or maybe HeapRef. The problem is exactly that rust chose a misleading name Box (boxed types are something entirely different in most languages) instead of the obvious C(++)/Java-like _ptr, ref, * or & notation/convention
- nicoburns 7y agoBoxed types in Java are basically the same thing: a heap allocated version of an otherwise stack-allocated type.
- axelf4 7y ago> instead of the obvious C(++)/Java-like _ptr, ref, * or & notation/convention That would be very misleading since Box represents a heap-allocated owned value
- SamReidHughes 7y agoI thought the name was pretty clear; when I saw it in some list of different kinds of Rust pointers, I knew what it was immediately. It doesn't matter if some people are confused, because you can just explain what it is in 3 seconds. What's important for such a ubiquitous type is that the name is short.
- enlyth 7y agoBecause everyone knows what an enum is, and that <A> will be a generic type, from first glance. There's nothing to guess, apart from Box being some kind of pointer abstraction. Looking at the second definition it's not immediately apparent what 'a' is and "Node a (Tree a) (Tree a)" seems just like a bunch of words concatenated by spaces, it has no apparent structure or meaning, unless you're used to writing Haskell/ML/Lisp/etc.
- pjmlp 7y agoOne needs to know Rust to actually understand that Box is the Rust's way to do heap allocation.
- the_af 7y ago> Because everyone knows what an enum is, and that <A> will be a generic type, from first glance That's false. A programmer coming from Python or Go won't know this. Nobody who hasn't been exposed to the extremely arbitrary generics syntax in Java-like languages will know about <A>.
- nicoburns 7y agoThere's no reason why it should be more familiar. But it is more familiar to the huge number of developers who are used to ALGOL/C family languages.
- atroche 7y agoThe word “should” can also be “used to indicate what is probable” (according to the OED). I think that's the way GP intended to use it. As in, "why is it probable that the syntax is more familiar?"
- loeg 7y agoLiterally the punctuation ("<>{}()") and lexical structure is more familiar to anyone who's written any C-family language (C, C++, Java, ...). I say this as a C programmer with more or less equal (near-zero) Rust and Haskell experience.
- HelloNurse 7y agoNode(A, Box<Tree<A>>, Box<Tree<A>>), is obviously nested (a Node contains an A and two Trees) and the trees are optional (they are contained in a Box, whose purpose is obvious without even knowing the language) | Node a (Tree a) (Tree a) might or might not be nested, given the cheerful taste for currying and juxtaposition without punctuation that prevails in Haskell syntax, and it isn't obvious what purpose the parentheses serve (just grouping ?) and whether the trees are optional.
- tom_mellior 7y agoHow is the Haskell example not "nested" according to your definition? It contains an "a" and two Trees, just like the Rust example. Nothing is optional. (There might be a Maybe or similar type, possibly hidden behind a type name, but it would still not be optional.)
- brians 7y agoTo be obvious that it’s nested, you need to know that < and > are used as approximations for ⟨ and ⟩. You need to know that they’re brackets, not operators. You need to know that “enum” means that commas in the next section are different than usual, but only one layer deep—check nesting carefully. You need to know about type parameters in either version. I had a similar experience learning my first ML: I couldn’t even tell how many words each word would gobble up, because I didn’t know the reserved words get. Syntax highlighting helped, and it’s not a problem after a week or two. It’s no worse than figuring out what’s a binary vs unwary operator in C and its descendants. Also: it’s not obvious to me that Box means optional/nullable. I’d expect it to mean a required non-null pointer to a heap element.
- HelloNurse 7y agoChildren of a non-leaf tree node must be optional because otherwise the node would be forced to have both children. It's therefore obvious that Box means optional; otherwise there would be a bare Tree<A> to represent a mandatory reference.
- 7y ago
- LandR 7y agoI would say the second one is more intuitive to me, it reads like I have a Tree type and it can be either a Leaf or a Node. The rust example to me isn't immediately obvious that it's an either / or situation other than that must be how an enum works (I know enums from other languages)
- perrohunter 7y agoBecause of the memory safety in rust, it’s now clear those left and child nodes could be missing since there’s no null in rust.
- saghm 7y agoGiven that GP already stated they don't know enough Haskell to translate all the examples, it seems pretty clear to me that by "familiar" they mean "in a language I'm familiar with".
- steveklabnik 7y agoIt ends up looking like a halfway point between the two. A little of column A and a little of column B.
- ur-whale 7y ago> but with a much more familiar syntax. This is actually one of my main two beefs with Haskell: . The language is really interesting from a feature point of view, but the syntax, oh man. Looking at Haskell code when you switch back and forth from a more conventional language (C/C++/JS/Java/C#/Python/etc...) is a major headache. I can switch from C++ to Python without a second thought. Not so with Haskell. . You can't really predict how something will actually execute, that's left to the language to decide. While in some situations this is a desirable feature, in many, it isn't at all, especially if you're writing performance critical code.
- jonsen 7y ago1. The language is really interesting from a feature point of view, but the syntax, oh man. Looking at Haskell code when you switch back and forth from a more conventional language (C/C++/JS/Java/C#/Python/etc...) is a major headache. I can switch from C++ to Python without a second thought. Not so with Haskell. 2. You can't really predict how something will actually execute, that's left to the language to decide. While in some situations this is a desirable feature, in many, it isn't at all, especially if you're writing performance critical code.
- jolmg 7y agoThanks. I wonder why people don't correct their text as soon as they notice how it renders. > You can't really predict how something will actually execute, that's left to the language to decide. If this is referring to order of evaluation, it's better to think that it's up to the code to decide, not the language. In a function application/call like: f a b c it is f, not Haskell, that will decide in what order a, b, and c will evaluate by the way in which it uses them. Haskell, the language, merely doesn't force the evaluation of arguments before evaluating a function.
- gabipurcaru 7y agoI've been using Haskell for quite a bit in production. My personal take, as an engineer who is generally skeptical of fancy language features: Plus: - The type system. It can make your life a huge pain, but in 99% of the cases, if the code compiles, it works. I find writing tests in Haskell somewhat pointless - the only places where it still has value is in gnarly business logic. But the vast majority of production code is just gluing stuff together - Building DSLs is extremely quick and efficient. This makes it easy to define the business problem as a language and work with that. If you get it right, the code will be WAY more readable than most other languages, and safer as well - It's pretty efficient Minus - The tooling is extremely bad. Compile times are horrendous. Don't even get me started on Stack/Cabal or whatever the new hotness might be - Sometimes people get overly excited about avoiding do notation and the code looks very messy as a result - There are so many ways of doing something that a lot of the time it becomes unclear how the code should look. But this true in a lot of languages
- verttii 7y agoWhat about runtime stuff? I've found Haskell is very good at abstracting away your concerns about the runtime considerations and sometimes it will come back to bite you. I mean all that stuff you want to see into when you're running your app in production, like caching, function invocation times, threads etc.
- gabipurcaru 7y agoCan't really comment on that - most of the code I use is built on the awesome Haxl[0] so we never have to worry about those things. I'm curious what other people think though [0] https://github.com/facebook/Haxl https://github.com/facebook/Haxl
- roar-of-time 7y agoYep, GHC is an incredible compiler and Haskell is an incredible language. If only Haskell had a package manager as slick as Cargo, I'd use it for just about everything.
- atoav 7y ago
- zimbatm 7y agoOne thing that makes programming difficult is how much context needs to be held in the live part of the brain. Past N items (let's say 4), the brain has to swap those values and it makes programming much much slower. Most of the article is spent explaining this sideways; with Haskell you need to hold less aspects in the head because they are either eliminated entirely (purity) or can be deferred to the compiler (types), ... What we learn is that Haskell is easier to implement tree-like structures. I think this is what most language proselytes are trying to convey in their articles. But don't talk about explicitly. Inevitably they will pick a task that is easy to achieve in the language because the developer environment aligns well for that use-case, and then let the reader infer that this applies to all programming tasks. Basically we are trying to benchmark humans, without building a proper model of how humans work. The next evolution in programming will be done by properly understanding how we work and interact with the computer.
- GaurVimen 7y agoThis is a great article! We need more of these comparison sort of things. > we can’t write a mutating method which changes a tree from a leaf to a node I was puzzled by this for a while. Then I realised that object oriented inheritance hierarchies have a problem that I've never grasped before: you can mutate your object but you can't mutate so that its (sub)type changes! Yet another reason that OO is poor for design. On the other hand the Haskell version doesn't support mutation either. I think this article would be better if it had used a persistent data structure in Python too.
- chungus 7y agotldr: I am NEVER nervous about refactoring some Haskell code. Good: After working in a variety of organizations using, typed but also dynamic languages I'm now writing all my back-end code in Haskell. I'm becoming more and more convinced that for multi-year, multi-programmer applications (a language like) Haskell is the only way to make it sustainable, while still being able to add features. Stephen Diehl has a great writeup on "what he wish he knew when he was learning haskell" http://dev.stephendiehl.com/hask/ http://dev.stephendiehl.com/hask/ It's difficult to say to someone "Just go read books for a couple of months because you need to understand purity, laziness, cross compilation, monad transformers (go read The Book of Monads), 20+ language pragmas. etc etc" It does however feel like I'm learning useful stuff, and it's a lot of fun to get an executable that runs FAST.
- gnud 7y agoML seems to be a much more developer-friendly approach to me. Eager evaluation, no problem "escaping" to imperative code, no "purity". All the benefits of functional programming, a good type system, and a great module system. I'm constantly sad that Standard ML is so outdated. No good tooling, no real unicode support, etc. At least we have ocaml and F#.
- toastal 7y agoPureScript is an strict ML too and even closer to Haskell than F# and OCaml as it doesn't have the object-oriented bits and is pure (doesn't allow the same level of side effects like mutability as those two without the very explicit 'unsafe' functions).
- fistOfKross 7y agoI got curious about Haskell some years ago because of a complete career disappointed with other languages. Ive put out some semi big apps in this language, that have been working well in production. I code for fun and Haskell is the most fun. Sure, there has been a couple of problems with tooling and its hard to find best practices, but I seem to be able to live with. I get a little depressed when having to work with other languages. For me its the end game.
- Beltiras 7y agoFriend of mine is always trying to convert me. Asked me to read this yesterday evening. This is my take on the article: Most of my daily job goes into gluing services (API endpoints to databases or other services, some business logic in the middle). I don't need to see yet another exposition of how to do algorithmic tasks. Haven't seen one of those since doing my BSc. Show me the tools available to write a daemon, an http server, API endpoints, ORM-type things and you will have provided me with tools to tackle what I do. I'll never write a binary tree or search or a linked list at work. If you want to convince me, show me what I need to know to do what I do.
- eterps 7y agoThis a 100%. If Haskell proponents focused more on stuff that is described in https://pragprog.com/book/swdddf/domain-modeling-made-functional https://pragprog.com/book/swdddf/domain-modeling-made-functi... instead of algorithms a lot more devs could use it in their day-to-day job.
- yakshaving_jgt 7y agoIt's all there to be used, it's just unfortunately Haskell proponents seem not to talk about it as much. Most of the discussion is around "interesting" stuff. My company does everything in Haskell, but it's almost all just boring plumbing code. APIs, JSON, databases, HTTP stuff, HTML templating, etc. It works great.
- Beltiras 7y agoCan you share any of your toolchain and stack?
- yakshaving_jgt 7y agoSure. Here you go. https://news.ycombinator.com/item?id=21024494 https://news.ycombinator.com/item?id=21024494 As for libraries we use heavily (in no particular order): Yesod, Persistent, Esqueleto, Lens, Lens-Aeson, Hedis, STM, Wreq, Shakespeare, Hspec.
- h91wka 7y agoHaskell is a beautiful research language. Its usecase is to supply subjects for PhDs and MScs, which it fulfills perfectly. Also it's extremely fun to learn and play with. I would never bring it to the production though, reasons being: 1) Production code should be understandable by an on-call person at 4 am. If business logic is buried under layers of lenses, monad transformers and arrows, good luck troubleshooting it under stress. And real systems do break, no matter type safety. 2) It's a research language, and a big part of the research is about control flow. And therefore haskell has _way too many_ ways to combine things: monad transformers of different flavors, applicative functors, arrows, iteratees, you name it. And libraries you find on hackage choose _different_ ways to combine things. In the business code you probably want to combine multiple libraries, and you inevitably end up with unholy mess of all these approaches. Dealing with it takes more time than writing business logic. 3) Developers look at these fancy research papers and try to reproduce them. As a result, very basic things become extremely hard and brittle. I saw a real-live example when applying a transform to all fields of a record took a team 2 days of discussion in slack, because "writing this manually?! it won't scale to record with 100 fields". 4) Architecture is extremely sensitive to the initial choices due to isolation of side effects. Because if you suddenly need to do something as simple as logging or reading a config in a place where it wasn't originally anticipated, you're in for a bumpy ride.
- ukj 7y ago>Architecture is extremely sensitive to the initial choices due to isolation of side effects. This is fundamentally why it's useless in practice. It requires you to anticipate/predict everything ahead of implementation. It requires you to be perfect at Waterfall ( https://en.wikipedia.org/wiki/Waterfall_model https://en.wikipedia.org/wiki/Waterfall_model ). Real-world problems laugh at such idealism.
- mic47 7y ago>Architecture is extremely sensitive to the initial choices due to isolation of side effects. Only if you choose to isolate all side effects from each other. Actually Haskell makes refactoring really easy, so you can adapt your implemention to changing requirements easily.
- euske 7y agoI think Haskell is conceptually cool, but I just can't stand its symbols and grammars. To me, "=>" means comparison and "|" means an OR, and I'm cringed to see $s and \s in a program code that makes it look like LaTeX. I also prefer the boundary of terms and expressions to be consistently marked up with parenthesis. I know this is just a matter of taste, but sometimes it affects your motivation a lot.
- ggm 7y agoI have had this the syntax is horrid conversation many times. I share your traits of how symbols are seen and mentally spoken clouding the concept. My adversaries argue from positions of clearly complete comprehension of the algebraic intent of these 'words' and they can't understand my confusion. It's like arguing with a native English speaker about illogical spelling, it just gets a "get over it" response.
- ur-whale 7y agoI 100% agree. Haskell is a very sad story in that regard: the language brings tons of cool features to the table only to turn away most of its potential customers because of how ugly and weird it looks.
- jolmg 7y ago> "=>" means comparison In what language? Did you mean ">=" or "<="? They mean the exact same thing in Haskell. > "|" means an OR It also means the same thing in Haskell. data Maybe a = Nothing | Just a "data of type `Maybe a` is either `Nothing` OR `Just a`." max a b | a > b = a | otherwise = b "max of a and b is either a when a > b OR b otherwise." odd x || x >= 5 "x is odd OR x is greater than or equal to 5" A cool thing about Haskell is that it lets you define new operators. In the parsec package, you get the operator <|>, which keeps the meaning of OR but works with parsers. csvCell = csvQuotedCell <|> csvNonQuotedCell "a CSV cell is either a quoted cell OR a non-quoted cell". > I'm cringed to see $s and \s in a program code that makes it look like LaTeX I don't think they're so common that the comparison is valid. $s implies Template Haskell, which should be used sparingly. \s implies lambdas, which are nowhere near as common as the use of backslashes in LaTex. > I also prefer the boundary of terms and expressions to be consistently marked up with parenthesis. The way you wrote this, makes me think you prefer to write 2 + 5 * 2 as 2 + (5 * 2). You can do that, just like in any other language. I don't think it's common to add parenthesis redundantly in any language though. If you actually meant something like preferring f x y to be written as f(x, y), it's not just a matter of taste. It's so the syntax makes sense with partial application. You can do f x y = ... g = f x h = g y and it would be more confusing to write f(x, y) = ... g = f(x) h = g(y)
- tom_mellior 7y agoThis is a good discussion of a problem that suits Haskell well, but it's unfair to Python in some respects. For example: I haven't read or written a lot of Python in a while, but would Python programmers really want to implement mutation in such a class by copying dicts around? The hand-wringing about "oh no, I wrote the condition as not is_node" is silly since one could just define an is_leaf method that can be used without negation. And "changing heapToList to return a lazy sequence makes it no longer return a list, oh no!" is just as silly, since one would of course not do that but define a separate heapToSequence (and probably base heapToList on that). Also: "pattern matching and algebraic data types which have massive, clear benefits and few (if any) downsides". They have downsides whenever your data is not tree-shaped. Yes, a lot of data is tree, but then a lot isn't. I work in compilers, which is often touted as a prime application of ML-family languages, and this is very true, but not 100%. If you can have sharing in your abstract syntax tree (like a goto node that might refer to a target node somewhere else in the tree), you start to have difficulties. And you get even more difficulties when you try to model control flow graphs and the like. Nothing insurmountable, but still things where it's suddenly good to have other tools than only algebraic datatypes. OCaml is good in this regard.
- platz 7y agoYou are free to use a Map in Haskell whenever it suits you. Nothing requires to to use ADTs when it would not make sense to do so.
- tom_mellior 7y agoSure, I said the issue was not insurmountable. But (and yes, I know Haskell programmers won't necessarily agree) there are contexts in which following a direct, mutable reference is superior to indirecting through a map.
- platz 7y agoSure, Desktop GUI programming tends to be one of those contexts. But I think those contexts are much rarer in Server APIs, and the internet has shifted the focus of programming from GUIs to APIs. I wouldn't recommend Hsakell for a desktop GUI, but it's excellent in the API world. It's more of a backend language.
- contravariant 7y agoWait, why do the leaves contain no data? What's the point of even adding them then? With data in the leaves you could easily do something like: @dataclass def Node: data: "Any" @dataclass def Tree(Node): left: Node right: Node using the new dataclasses module. You could also add a type parameter to the above if you really wanted to. The pattern matching will need to be done manually though, following python's philosophy of duck-typing. Edit: An alternative involves abusing the pattern matching that python does have to write things like: data,*subnodes = myTree for node in subnodes: # etc but whether that's really a good idea is debatable.
- ggm 7y agoThe leaves are intended to stand for more complex leaves the actual data type held in the tree is boring, only its properties of nodes and leaves matter. (I think)
- tom_mellior 7y ago> Wait, why do the leaves contain no data? What's the point of even adding them then? You need something to represent a completely empty tree. You also need something to represent in a Tree node that "there is no child here". It makes sense to use the same thing for both. In Python and other languages with nullable references you can just use None (or null, or ...) for this. But ML-family languages have no nullable references. You could use option types instead, but that would look pretty complex, something like (my Haskell is rusty): data Tree a = Maybe (TreeStructure a) data TreeStructure a = TreeNode (Maybe (TreeStructure a)) (Maybe (TreeStructure a)) (You should be able to use Tree a in the definition of TreeNode, but I wanted to show the "real" structure, which you would also have to care about when pattern matching.) It's easier to have an empty leaf instead. Personally I would possibly call it EmptyLeaf or maybe NoTree instead of just Leaf.
- contravariant 7y agoAt this point we're basically discussing what kind of tree you want. Including if you truly need an empty tree (which is maybe necessary if you want to do Monad like operations that don't return a result, but then doing so on a tree is pretty weird in the first place, and I'm not entirely sure what you'd do if a node in the middle of the tree returned Nothing, do you just throw away its children?). The best design will depend on what you need a tree for as well as in what language you will implement it. But yeah if you want an empty tree I'd recommend just using None in python. You'll just need checks like 'if node' where you'd otherwise have pattern matching; you could improve QoL a little by defining an iterator over the existing children. If you really want a separate object then you run into all kinds of annoying stuff, including the fact that by default python will allocate separate objects for all of them, which is 1) slow and 2) bad for memory usage.
- functionalias 7y agoBeing a good person is a goal in itself. In the same way, Haskell is a good language, it's a moral language. Of course this causes some pain, but it's worth it.
- unixhero 7y agoI wouldn't know. It was impossible to learn.
- ur-whale 7y ago>I wouldn't know. It was impossible to learn. People shouldn't downvote you: the sarcasm bit is funny, and it does actually point out to one of the major reason Haskell is not gaining more acceptance in spite of its many great features: . the syntax is completely alien (to the point of turning quasi APL-ish in some cases) and scares away potential users. . the community is so focused on esoteric stuff that the "how do I do X that's super easy to do in traditional languages" is completely missing from the conversation.
- jonsen 7y agothe syntax is completely alien (to the point of turning quasi APL-ish in some cases) and scares away potential users. the community is so focused on esoteric stuff that the "how do I do X that's super easy to do in traditional languages" is completely missing from the conversation.
- the_af 7y agoThe syntax is not alien. Care to give an actual example that confused you?
- TheSmoke 7y agoofftopic: if anyone's interested -- Standard Chartered Poland is looking for Haskell hackers: https://twitter.com/MikolajKonarski/status/1178272315815219200 https://twitter.com/MikolajKonarski/status/11782723158152192...
- axilmar 7y agoTo play the devil's advocate here: no post speaks about any serious disadvantages of Haskell. So, for a programming language that has so much to offer, why isn't it adopted more? Could it be that it doesn't actually increase productivity to such a degree to justify the cost of change? Legit question, I am not trying to be a troll.
- reikonomusha 7y agoI can’t say for Haskell, but I can say for Lisp, which similarly gets these “look how great” articles but also similarly doesn’t see a huge up-tick in usage. Whether you’re a student fresh out of school, or you’ve been unemployed for 10 years as a sysadmin, or you’re an expert programmer already, Common Lisp is accessible to you. Those examples are real; they’re backgrounds of folks I either used to or currently work with. Being paid helps immensely. So it’s not that the language is unlearnable, unreadable, or out-of-reach. (The pot-shots that random commenters in forums like these take on the language are usually shallow or even outright wrong.) In some cases, it’s even demonstrated to be asymptotically more productive. So what’s the deal? I personally think it’s just that productivity isn’t in and of itself incentivizing enough. You know Python and C++, you’re relatively proficient at them, you know how to get the job done with them, why learn something new? Haskell/Lisp won’t get you a job (necessarily), it won’t allow you to do something with a computer that you fundamentally couldn’t do before, and it’ll suck up a lot of your time to figure out what’s going on with them. Moreover, there’s no big organization behind it (like Mozilla or Facebook or Microsoft or ...) so where’s the credibility? A bunch of researchers at some university? A bunch of open-source hackers? I think one has to be personally invested in becoming a broadly more knowledgeable and more skilled programmer, just for the sake of it, and (IME) most people aren’t like that. I think one has to also have a penchant for finding simpler or more fundamental ways of solving problems, and that has to turn into an exploratory drive. Even if one is like that, learning Haskell is one of a hundred possible paths to improve oneself. My comment shouldn’t be misconstrued as supporting a mindset of it being OK to just know a couple languages well. I think the hallmark of an excellent programmer is precisely this broad knowledge of not just tools, but ways of thinking, in order to solve the gnarly problems that come up in software.
- agentultra 7y ago
- tu7001 7y agoI think we can code ADT in Python: https://github.com/lion137/Functional---Python/blob/master/trees_as_class.py https://github.com/lion137/Functional---Python/blob/master/t...
- lidHanteyk 7y agoPython may be terrible, but this poster doesn't know Python at all. Here's how to fix the first snippet: leaf = object() Huh, that's funny, it's shorter than the Haskell? Why is that? Let's keep going. def merge(lhs, rhs): if lhs is leaf: return rhs if rhs is leaf: return lhs if lhs[0] <= rhs[0]: return lhs[0], merge(rhs, lhs[2]), lhs[1] return rhs[0], merge(lhs, rhs[2]), rhs[1] Ugh. My mouth tastes funny. Livecoding on this site is always disorienting. I need to sit down for a bit. Exercise for the reader: Continue on in this style and figure out whether the Haskell really deserves its reputation for terseness and directness. Edit: I kept reading and was immediately sick. __dict__ abuse is a real problem in our society, folks. It's not okay. def insert(tree, elt): return merge(tree, (elt, leaf, leaf)) The Haskell memes are growing stronger as I delve deeper into this jungle. The pop-minimum function here is a true abomination, breaking all SOLID principles at once. I can only imagine what it might look like in a less eldritch setting: def popMin(tree): if tree is leaf: raise IndexError("popMin from leaf") return tree[0], merge(tree[1], tree[2]) We continue to clean up the monstrous camp. def listToHeap(elts): rv = leaf for elt in elts: rv = insert(rv, elt) return rv The monster...they knew! They could have done something better and chose not to. They left notes suggesting an alternative implementation: def listToHeap(elts): return reduce(insert, elts, leaf) Similarly, if we look before we leap: def heapToList(tree): rv = [] while tree is not leaf: datum, tree = popMin(tree) rv.append(datum) return rv And again, the monster left plans, using one of the forbidden tools. We will shun the forbidden tools even here and now. We will instead remind folks that Hypothesis [0] is a thing. Haskell's an alright language. Python's an alright language. They're about the same age. If one is going to write good Haskell, one might as well write good Python, too. [0] https://hypothesis.works/ https://hypothesis.works/
- newen 7y agoSo `tree` is either a `tuple` or an `object`? Seems pretty terrible in terms of typing.
- lidHanteyk 7y agoThe original was not better. More importantly, recall that Haskell's type system is unsound, so it's not like you can trust your Haskell code either. Just because it type-checks does not mean that it works. In either language, you'll want to write some tests. I mentioned Hypothesis for Python; for Haskell, there's also QuickCheck.
- whateveracct 7y agoI've worked at multiple Haskell shops. They've all had problems. None of the problems were actually attributable to Haskell..but Haskell was an easy target for blame by management. I'd say that's Haskell's biggest problem in a professional setting. I know Haskell and Go about equally. Meaning I know all the language features & common libs & have a grip on their runtimes. Go on day 1 was way easier to write and understand than Haskell on day 1. Now that I've normalized their learning curves, Go didn't get much easier to work with. Haskell did - I use my brain way less when writing Haskell than when writing Go. But even then, Haskell or Go. It's all just the same stuff. I've pretty much given up talking on the Internet to people about Haskell. Arguing against some of the pts in this thread about how Haskell isn't good for production. I'll continue to write Haskell for pay for the foreseeable future. If I'm lucky, I'll do it the rest of my career. I don't see any reason why not.
- proc0 7y ago> ..but Haskell was an easy target for blame by management. I'd say that's Haskell's biggest problem in a professional setting. I would say that's a software company's biggest problem instead. I really don't understand how someone with little or no coding experience can be in a leadership position with other programmers who are supposed to be problem solvers and have all the details of how to build something. The bigger the gap in knowledge, the more communication breaks down and the hierarchical structure becomes useless.
- whateveracct 7y ago> someone with little or no coding experience can be in a leadership position I had one where the leader in question had coding experience but didn't know Haskell at all. Despite this [1], they tried to read some code (that the Haskellers has no issues with) and couldn't, so he deemed the codebase unreadable and eventually called for a rewrite. Worse, during the debate about the rewrite, there was constant discussion about how the code was unreadable and bad, but it was never sourced to this leader. Instead it was asserted with weasel words only. [1] Maybe it was because of this..this leader was driven by confidence in their experience and seniority.
- 7y ago
- chowells 7y agoI have to disagree with the thesis here in its entirety. ADTs and pattern matching are not what makes Haskell good. Every article like this one just serves to show people the non-compelling bits of Haskell. The parts you can use in every other language, if you want to. The parts of Haskell that make it a good language aren't the things that you can just write a tutorial for. They're about software engineering, not code snippets. Purity and immutability remove entire classes of bugs caused by spooky action at a distance. When you assert this, people claim "I don't have those bugs", forgetting about the time someone else changed a function they wrote to mutate one of its arguments, breaking code three steps up the call chain. Parametric polymorphism documents what information a function cannot use within its definition. If you point this out, people ask what good that serves. There's no way to explain how much easier it is to get things done when you can write a function and know that no matter what values are passed in, there cannot be special cases that trip you up. I see people try to explain why the `Maybe` type is better than null values, and have their explanations rejected with "You still have to check for it. All you're doing is changing the syntax of the check." I've seen variations on that theme in maybe 10 different HN threads over the last 6 years. When all you talk about is ADTs and pattern matching, why would anyone ever look at the bigger impact of the type system? The relevant detail here is that an `Integer` can never be null, not that you use `Maybe Integer` to talk about potentially missing values. Further in that same direction, I see people say that the `IO` type just complicated things because your program has to do I/O anyway, so it always needs to be in `IO`. This is exactly the same as the `Maybe` problem, but that similarity is even further from being addressed by articles about pattern matching and ADTs. No, the similarity isn't "monads". Anyone who talks about them here has missed the point entirely. The point is that parametric polymorphism completely prevents distinguishing IO values from non-IO values, so code that's not written to work with IO values cannot do IO accidentally. There are a lot more cases, especially when you get into more sophisticated things possible in the type system using ghc extensions like generalized algebraic data types or higher-rank types. But all of the reasons you should be using Haskell in reality come down to practical large-scale software design concerns. The language lacks features that make several common classes of bugs possible. It makes several other common classes of bugs take a lot more work to implement than the non-buggy way to solve the same problem. These aren't things you can just write a short article about. They're things that require years of experience and introspection to see are even problems, and a willingness to accept that a lot of the problem is the ecosystem, not an individual failure to execute. None of that fits in an article. I think articles about how great pattern matching and ADTs are make the language look worse, because anyone with some experience can say look at what's actually happening and say "I can do that in <other-language>, Haskell clearly doesn't have anything to offer." In other words - stop writing these articles. They drive people away from Haskell, not encourage them to look at the good parts.
- cannabis_sam 7y agoIt’s hilarious to read all kinds of rationalizations for why haskell is not useful. Servant + Aeson beats any api backend in any language, period. If you combine that with Elm on the frontend you’ve got a great onboarding path for new devs to learn enough haskell to work on the backend. Of course, for production, ignore lenses, monad transformers, free monads, effect systems, etc. They’re awesome, but the complexity is not worth it in practice at this time.
- acroback 7y agoThis article reminds of my coworker, touts Haskell all the time, ends up writing shitty Java code which is difficult to understand and performs like molasses. Real world is not perfect, it is immutable with plenty of side effects. Using Haskell for day to day messy work is not trivial and should not be considered IMO, u nless you have Haskell gurus all around. I would rather take a dumb language like Go or Java over Haskell for work code.
- mbo 7y ago> Real world is not perfect, it is immutable with plenty of side effect Perhaps we should use a language that is immutable and can reason about side-effects. Like Haskell?
- haolez 7y agoHaskell seems cool, but if I’m going to invest time in a different programming paradigm, I’m more curious about APL/K/J. They seem more useful as well (to me).
- _bxg1 7y agoPractically speaking what I've heard is that the value of learning Haskell isn't so that you can then go use Haskell, it's so that you can then go write code in other languages as if it were in Haskell
- haolez 7y agoI think that’s unfair. Haskell is used in the real world to solve really hard issues, like anti-spam at Facebook. I’m simply more impressed by array-oriented languages :)
- patientplatypus 7y agoThe problem with Haskell is that it's smarter than most developers. You can study really hard and maybe you'll be good at Haskell. And then you'll find that there are no common libraries for the things you want to do because all the other developers were writing them in Python. Such is life.
- MadWombat 7y agoThis is about as far as I got with this... "While it solves the problem of methods, and the mutation problem, it has a serious bug. We can’t have None as an element in the tree!" Uhm... what?! Why not? You check that your left and right are None and if they are it is a leaf. And if they are not it is not. What your data value is doesn't matter and you can have as many None values in the tree as you like. Your tree doesn't need leaves to define where it ends, it ends when there are no more branches.
- oisdk 7y agoWhat about the singleton tree with just None in it? As in, what's the difference between `node(None, leaf(), leaf())` and `leaf()`? Or the following: x / \ / \ / \ y None / \ / \ / \ / \ Leaf Leaf Leaf Leaf
- MadWombat 7y agoThis x / \ / \ / \ y None / \ / \ / \ / \ Leaf Leaf Leaf Leaf Looks like this. x / \ / \ / \ y None There is no reason to explicitly define leafs
- oisdk 7y agoBut then wouldn’t the right node with None in it be the same as a leaf? Could you specify what you mean in code maybe? If you don't explicitly define leaves than how can you represent the empty tree?
- MadWombat 7y agohere, as I said, there is no need to represent an empty tree https://gist.github.com/MadWombat/798c6d993a7d2ac4ac74d6624a9a56b4 https://gist.github.com/MadWombat/798c6d993a7d2ac4ac74d6624a...
- ekimekim 7y agoI think python was a poor comparison here. The claim "python doesn't have algebraic data types" doesn't really make sense. Algebraic data types let something be an X or a Y. In python, everything can be an X, or a Y, or a Z, or anything else. In the tree example, an ideomatic tree structure in python would just be a 3-tuple (left, right, value). There's no need to define anything. Don't get me wrong, I'm all for algebraic data types and think every statically typed language should have them, but it's nonsensical to talk about them in the context of a dynamically typed language. The author commented elsewhere on this page that the article was mostly a response to missing these features in golang - I think that would've been a much clearer comparison that showed what you were really missing.
- zapzupnz 7y agoFor those who were wondering about seeing this in Swift. You probably weren't, and I'm aware I could've leaned a bit harder on things that were built-in, but I was basically trying to meet in the middle between representing the Haskell code as written in the interview and something vaguely Swifty. https://gitlab.com/snippets/1900852 https://gitlab.com/snippets/1900852
- deleted 7y ago[deleted]