| Here's a handful of things I really appreciate about Haskell, although some of this apply to other ML family languages as well: 1.) Algebraic Data Types let you enforce a huge amount of correctness in your programs simply by how you define your types. For example, say you have a data type that represents a player's state in a game. If the player is alive, he has a "HP" and "inventory" record. If the player is dead, he should just be dead—HP and inventory may or may not be set to 0 and None, respectively. In C or OOP languages, you just get a player object/struct and you have to enforce this state logic manually, and you can easily write a function that puts the player in an inconsistent state (player.alive = False, but player.HP = 15). In Haskell, you can define the player such that code that produces this kind of inconsistent state will not compile. Of course, you should still write tests in Haskell, but it's amazing to me that the type system can catch the vast majority of programming errors before your program even compiles. It takes longer to get something up and running, but you make up for this up front cost with long term gains in maintainability. 2.) Functional purity enforces two very useful properties: a.) Data is never mutated by accident. This ensures you never have to look beyond the scope of the function you're working on (or closing over, in some cases) to know what's going on. You can then compose these functions to create more complex programs. b.) When you do need mutability and side effects to happen, Haskell forces you to be very explicit about this and enforces a strict separation between "pure" and "effectual" code. This seems arbitrary until you realize that almost all of your errors not caught by the compiler happen because of IO. Whereas you have complete control over the pure part of your program, IO is nondeterministic and full of exceptions and edge cases. Separating this part of your code makes it far easier to reason about what's happening, adding to maintainability. As a side note on the last point: people make the argument that this separation makes Haskell impossible to do printf debugging. Not true—the standard library provides ways of circumventing the type system specifically for this reason. 3.) "Monads" and other fancy sounding abstractions can be hard, but with practice they become as intuitive as inheritance in OOP. The real barrier to entry is the awful, awful documentation everywhere. I make no apologies for that: it's just really shitty and the community needs to do a hundred times better. |
False. In OOP you can do this using the visitor pattern. The difference is that Haskell makes this real convenient, with its algebraic types feature baked into the language, while OOP makes it very cumbersome.
> As a side note on the last point: people make the argument that this separation makes Haskell impossible to do printf debugging. Not true—the standard library provides ways of circumventing the type system specifically for this reason.
It's still far more annoying when the language is lazily evaluated and has Haskell syntax.