Hacker News new | past | comments | ask | show | jobs | submit login

I was a college dropout and self taught bash and python programmer and quite some time ago, I read about Haskell, decided to teach myself to use it, and then realized I had absolutely no idea what programming actually was, and basically spent the next 15 years teaching myself computer science, category theory, abstract algebra and so on, so that I could finally understand Haskell code.

I still don't understand Haskell, but it did help me learn Rust when I decided to learn that. And I think I could explain what a monad is.

edit: It's a data structure that implements flat map. Hope this saves someone else a few years of their life.




> I still don't understand Haskell

It's not you. Haskell has very bad syntax. It's not hard to understand it, it you rewrite the same things in something saner. Haskell was developed by people who enjoy one-liners and don't really need to write practical programs.

Another aspect of Haskell is that it was written by people who were so misguided as to think that mathematical formulas are somehow superior to typical imperative languages, with meaningful variable names, predictable interpretations of sequences of instructions etc. They, instead, made it all bespoke. Every operation has its own syntax, variables are typically named as they would in math formulas (eg. X and X'). This makes no sense, and is, in fact, very harmful when writing real-world programs, but because, by and large, Haskell never raises to the task of writing real-world programs, it doesn't deter the adepts from using it.


Just to give a different pov I find Haskell very intuitive, and particularly I find that code written by other people is very easy to understand (compared to Java or TypeScript at least).

And by the way x and x' are totally fine names for a value of a very generic type (or even a very specific type depending on the circumstances), as long as the types and the functions are decently named. I mean, how else would you call the arguments of

splitAt :: Eq a => a -> [a] -> [[a]]

?

There is no need for anything more complex than

splitAt x xs = ...


> I mean, how else would you call the arguments of > splitAt :: Eq a => a -> [a] -> [[a]]

Those don't seem to be names of parameters, but rather of types. It's missing parameter names entirely.

I spent a good 2 minutes looking at that signature trying to figure it out (and I've read some Haskell tutorials so I'm at least familiar with the syntax). This would've helped:

    def split_by<T>(separator: T, list: List[T]) -> List[List[T]]
`sep`, `separator`, `delim`, `delimiter` would've been good names.


> Those don't seem to be names of parameters, but rather of types. It's missing parameter names entirely.

The rest of the definition is at the end, to see it as a whole:

  splitAt :: Eq a => a -> [a] -> [[a]]

  splitAt x xs = ...
To clarify, I assumed that by using the constraint `Eq a` and the name splitAt there was no need for extra clarification in the names of the parameters but apparently I was wrong.


I think some of the confusion is because you're referring to the type variables as parameters. Parameters and type variables are not the same thing. A is a type variable, X is a parameter in your example.


No, you're right. It is perfectly clear from the type signature


That's what (some) other people do. None of that stops you writing Haskell in whatever style you want, with meaningful variable names, curly braces and semicolons!


Unfortunately, writing isn't even half the battle. Before you start writing, you need to read a lot. And Haskell code is, in general, atrocious. It always feels like there was a normal way to do something, but the author decided to chose the most convoluted way they can imagine to accomplish the same thing for the sake of a bizarre fashion sense.


You knew Paul Hudak, Simon Peyton Jones, Phil Wadler, etc? Were they thinking about the benefits of mathematical formulas over program counters and procedural keywords when designing Haskell?

I was under the impression from the History of Haskell [0] that they were interested in unifying research into lazy evaluation of functional programming languages.

> This makes no sense, and is, in fact, very harmful when writing real-world programs,

Gosh, what am I doing with my life? I must have made up all those programs I wrote on my stream, the ones I use to maintain my website, and all the boring line-of-business code I write at work. /s

In all seriousness, Haskell has its warts, but being impractical isn't one of them. To some purists the committee has been overly pragmatic with the design of the language. As far as functional programming languages go it's pretty hairy. You have "pure" functions in the base libraries that can throw runtime exceptions when given the wrong values for their arguments (ie: the infamous head function). Bottom, a special kind of null value, is a member of every type. There exist functions to escape the type system entirely that are used with some frequency to make things work. The committee has gone back more than once to reshape the type-class hierarchy much to the chagrin of the community of maintainers who had to manually patch old code or risk having it not longer compile on new versions of the base libraries. These are all hairy, pragmatic trade-offs the language and ecosystem designers and maintainers have had to make... because people write software using this language to solve problems they have and they have to maintain these systems.

[0] https://www.microsoft.com/en-us/research/wp-content/uploads/...


You don't need to know the author personally to appreciate the result of their work...

> Gosh, what am I doing with my life?

I would ask the same question, but unironically. No, you didn't make up those programs of course. I didn't claim that real-world programs are impossible to write in Haskell. I claimed that Haskell is a bad tool for writing real-world programs. People make sub-optimal decisions all the time. That's just human nature... choosing Haskell for any program that would require debugging, long-term maintenance, cross-platform UI, or plenty of other desirable properties is just a very bad choice. But people like you do it anyways!

Why? -- there are plenty of possible answers. If I wanted to look for the flattering answers, I'd say that a lot of experienced and talented programmers like Haskell. So, choosing to write in Haskell for that reason isn't such a bad idea. But, if I wanted to judge Haskell on its engineering rather than social merits: it has very little to bring to the table.


Strange. In my experience Haskell is the best language for long-term maintainability! I can actually come back to code I've written years ago and understand what it does. I've never experience that with another language.


This is not really what maintainability means to me. To me, it just means you have a good memory.

To be able to maintain something you need to be able to transfer the ownership of the piece of code to someone else. You need to be able to amend the code easily to extend or to remove functionality. It means that the code can be easily split into pieces that can be given to multiple developers to work simultaneously towards a common goal.

Haskell scores poorly on any of those points.

It's very hard to transfer ownership because Haskell programs have too much bespoke syntax that anyone but the original author will not be familiar with. Haskell programs are very hard to understand by executing them because there's no chance of a good step debugger due to the language being "lazy". Haskell programs are always "full of surprises" because they allow a lot of flexibility in the interpretation of the same symbols. The problems C++ programmers complain about when faced with operators overloading are the kind of things Haskell programmers call "Tuesday".

"Pure" functions are a lot harder to modify to add functionality. Typically, such modifications would require swiping changes across the entire codebase. One may argue that this preserves "single responsibility" constraint, but in practice it means a lot more work.

Objects and modules were advertised as a solution to code modularity -- another necessary quality for maintainability. While Haskell has modules, it doesn't really have smaller units of encapsulation other than functions. If two programmers are tasked to work on the same module, they aren't going to have a good time.


> To be able to maintain something you need to be able to transfer the ownership of the piece of code to someone else. You need to be able to amend the code easily to extend or to remove functionality. It means that the code can be easily split into pieces that can be given to multiple developers to work simultaneously towards a common goal.

> Haskell scores poorly on any of those points

Interesting. I work at a company with over a hundred people committing to a Haskell code-base that runs our entire back-end. As far as I can tell we're continuously shipping code several times a day, every day, with very low impact on our service level indicators.

When we do have production issues they're rarely attributed to Haskell. I can think of one incident in 3 years where a space leak was caught in production. It was straight forward to address and fix before it impacted customers.

In practice, Haskell has been amazing to work with. I just rewrote over a thousand lines of code and shipped that to production without incident. I've never had that go off easily in any other language I've worked with (and I've been around for over twenty years and worked in everything from C, C++, Python, and JS).


I worked for a company that had a product with several million lines of C, couple hundreds of lines of Java, same for Go, Ruby and Python.

And it worked great! And you know why? -- The programmers were skilled at what they were doing. There were about 60 employees in total, and they managed a relatively big codebase for a complicated product (distributed filesystem). Btw, our build system was written in Haskell.

And why do I mention this? -- because I also worked in many other companies, who used all the same languages, typically for much smaller codebases compared to the number of people working on them. And the effects were usually awful.

In conclusion: the choice of language doesn't define the outcome. You may be successful choosing a bad language if you hire good programmers and other stars align to make it happen. You can also easily fail if you use a good language, but other, more important conditions don't hold.

Your individual success is at best an indication that it's possible to use Haskell to achieve your goals. It doesn't mean it's a good tool. You didn't even try to have a test that'd compare Haskell to other languages, you don't have any explanation for why Haskell is good for your case. It just worked "somehow".

What I say, I saw from a more general perspective, and with some justification. But if you need examples rather than justification: at one point in the past, Japanese high-schools used Haskell to teach computer science. I was able to compare the experience to Basic and Pascal which I experienced personally. In the hands of a mediocre-bad programmer Haskell is an awful tool and produces far worse results than Basic or Pascal. And, surprise, most programmers in the world are mediocre-bad. You cannot take your example and extrapolate from it that if everyone used Haskell software would've been better. In fact, there's every indication it wouldn't. In most likelyhood it'd be a lot worse.


I’ve been in this industry for over twenty years. I’ve written a fair share of code in other languages. There’s not enough empirical evidence to suggest that one language is better than any other.

My example is only a counter argument that Haskell isn’t suitable because of the reasons you stated. Clearly it can be maintained, work can be split among groups, and delivered with reasonable efficiency… like a lot of software can be in other languages.


I don't know what to tell you. I've been successfully using Haskell in production for over ten years, and it's the most maintainable language I've used for a variety of reasons, including the one given in my message above.


I think we can drop the "real-world," qualifier as it is unlikely there is an "imaginary-world" that we write programs for.

What engineering merits did you have in mind?


Real world in this contexts contrasts the world of programs that nobody needs or uses. Programs that are written for amusement or with no stringent requirements.


> it is unlikely there is an "imaginary-world" that we write programs for

I think academia is typically what's meant as an imaginary world, along with play that may be in reference to no world at all.


I think that's a good starting definition for programmers, but still could cause confusion when you run into something like IO in Haskell. IO isn't really a data structure, and it's hard to fit the "flat map" concept to it.


If you want you can still keep this point of view, by saying that IO is conceptually a data structure that builds a description of what the program does. In this point of view it follows that there is another, impure program that interprets the IO data structure and actually performs the computations

(Of course in practice IO isn't implemented like this, because it would be too slow)

(But in every other language, like Javascript or Python, you can define IO as a data structure. Or even in Haskell itself, you can define for eg. a free monad that gets interpreted later, and it can be made to be just as good as IO itself, though typically people make it less powerful than IO)

However note that every other "computational" monad (like the list monad or the Cont monad) actually is a data structure, even though they describe effects just like IO does. This is because IO is the only possible exception to the "monads are data structures" thing in Haskell (if you don't subscribe to the above view), because Haskell doesn't let you define types that aren't data structures

The only issue with this point of view is that you now need to say what flatMap means for things that are not shaped like arrays. Eg. does it make intuitive sense to flatMap a tree? (A retort is that it must make sense, whatever you call this operation; and flattening a tree means to turn a tree of trees into an one-level tree)




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: