> Many programmers encounter statically typed languages like Java or C++ and find that the compiler feels like an annoyance. By contrast, Haskell’s static type system, in conjunction with compile-type time checking, acts as an invaluable pair-programming buddy that gives instantaneous feedback during development.
Many programmers find that Java or C++'s static type system, in conjunction with with compile-type time checking feels like an annoyance. Unlike... the very same statement about Haskell? That's... that's quite a weak claim, to say the least.
> a signature like Int -> Int -> Bool indicates that a function takes two integers and returns a boolean value... this allows a programmer reading Haskell code to look only at type signatures when getting a sense of what a certain piece of code does. For example, one would not use the type signature above when looking for a function that manipulates strings, decodes JSON, or queries a database.
So... Type signature `Int -> Int -> Bool` can be used for a function that does any of the following things: manipulates strings, decodes JSON, or queries a database? How does that make it easier to deduce what a function does by "looking only at type signature"?
> Another feature of a pure functional programming paradigm is higher-order functions, which are functions that take functions as parameters.
As in: available in almost any language these days, and not exclusive to a "pure functional programming paradigm".
> One of the common development workflows we employ is relies on a tool called ghcid, a simple command line tool that relies on the Haskell repl to automatically watch code for changes and incrementally recompile. This allows us to see any compiler errors in our code immediately after saving changes to a file. It’s not uncommon for us to open only a terminal with a text editor and ghcid while developing applications in Haskell.
As in: Modern IDEs don't require you to run external tools to monitor your code for changes and highlight errors.
> a common refactoring workflow is to make a desired change in one location and then fix one compiler error at a time until the program compiles again.
As in: Modern IDEs let you do large-scale refactoring in one go, at a press of a button.
> The type system can protect us from making mistakes when changing the rules of our domain.
It can't. The example provided can't stop you from doing `case status of Paid -> delete invoiceNumber`. You have to invest significantly in a type-based DSL to prevent that from happening. But then, who will test your DSL?
> Haskell enables domain-specific languages, which foster expressiveness and reduce boilerplate
DSLs where all the rage 5-10 years ago. In reality, they are overhyped and are used very sparingly, for obvious reasons: DSLs are languages. They have to be designed, developed, maintained. Errors in your DSL will most likely harder to find and debug than in your regular program.