Of all the languages in this book, Haskell was the only one created by committee. After the proliferation of purely functional languages with lazy semantics, a committee was formed to build an open standard that would consolidate existing capabilities and future research. Haskell was born, with version 1.0 defined in 1990. The language and community have grown since then.
Haskell supports a wide variety of functional capabilities including list comprehensions, lazy computing strategies, partially applied functions, and currying. In fact, by default, Haskell functions process one parameter at a time, using currying to support multiple arguments.
The Haskell type system provides an excellent balance of type safety and flexibility. The fully polymorphic template system allows sophisticated support for user-defined types and even type classes that fully support inheritance of interface. Usually, the Haskell programmer is not burdened with type details except in the function declarations, but the type system protects users from all kinds of type errors.
As with any pure functional language, Haskell developers must be creative to deal with imperative-style programs and accumulated state. I/O can also be a challenge. Fortunately, Haskell developers can rely on monads for that purpose. A monad is a type constructor and a container that supports basic functions to wrap and unwrap functions as values. Different container types provide different computational strategies. These functions allow programmers to chain together monads in interesting ways, providing do syntax. This syntactic sugar allows imperative-style programs with certain limitations.
Since Haskell takes the absolute approach of pure functions with no compromise, the advantages and disadvantages can be often extreme. Let’s break them down.
If you like strong typing (and maybe even if you don’t), you’ll love Haskell’s typing system. It is there when you need it but not when you don’t. The type system can add a helpful level of protection from common errors, and they can be caught at compile time rather than run time. But the extra safety is only part of the story.
Perhaps the most interesting part of a Haskell type is how easy it is to associate new types with new behaviors. You can build up sophisticated types from the ground up. With type constructors and classes, you can even customize extremely complex types and classes such as Monads effortlessly. With classes, your new custom types can take advantage of existing Haskell libraries.
The Haskell language has fantastic power. From an abstract sense, it has everything you need to express powerful ideas concisely. Those ideas encompass behavior through a rich functional library and a powerful syntax. The ideas extend to data types where you can create types, even recursive types that bind the right functions to the right data without excessive syntax. In an academic setting, you can find no stronger language for teaching functional programming than Haskell. Everything you will need is in there.
Pure programming models can radically change the way you approach problems. They force you to leave old programming paradigms behind and embrace different ways of doing things. Pure functional languages give you something you can depend on. Given the same inputs, a function will always return the same values. This property makes it much easier to reason about programs. You can sometimes prove that a program is correct, or not. You can also be free of many of the problems that come from depending on side effects, such as accidental complexity and unstable or slow behavior in concurrent situations.
Once upon a time, dealing with functional languages meant dealing with recursion. Lazy computing strategies offer a whole new set of strategies to deal with data. You can often build programs that perform better and take a fraction of the total lines of code that another strategy might take.
Some of the most important and influential languages such as Pascal grew up in academia, benefitting greatly from research and use in that setting. As the primary teaching language for functional techniques, Haskell continues to improve and grow. Though it is not fully a mainstream language, you’ll always be able to find pockets of programmers to do important tasks.
You know by now that no programming language is perfect for every task. Haskell’s strengths typically have a flip side as well.
Being a pure functional language offers some advantages but also a set of headaches. You might have noticed that programming with monads was the last part of the last chapter in a book about programming languages, and rightfully so. The concepts are intellectually demanding. But we used monads to do some things that were trivial in other languages, such as write imperative-style programs, process I/O, and even handle list functions that may or may not find a value. I’ve said it before about other languages, but I’ll say it again here. Though Haskell makes some hard things easy, it also makes some easy things hard.
Certain styles lend themselves to certain programming paradigms. When you’re building a step-by-step algorithm, imperative languages work well. Heavy I/O and scripting do not lend themselves to functional languages. Purity in one man’s eyes may seem like failure to compromise in another.
Speaking of compromise, you can really see the differences in the approach of Scala and Haskell. Though both are strongly typed, both have radically different philosophies. Scala is all about compromise, and Haskell is all about purity. By making compromises, Scala has initially attracted a much bigger community than Haskell. Though you can’t measure success by the size of a programming community, you must have sufficient numbers to succeed, and having more users lends more opportunity and community resources.
The monad is not the only intellectually demanding concept in Haskell. Currying is used in every function with more than one argument. Most basic functions have parameterized types, and functions on numbers often use a type class. Though the payoff may be well worth it in the end, you must be a strong programmer with firm theoretical footing to have a fighting chance of succeeding with Haskell.
Of the functional languages in the book, Haskell was the most difficult to learn. The emphasis on monads and the type system made the learning curve steep. Once I mastered some of the key concepts, things got easier, and it became the most rewarding language I learned. Based on the type system and the elegance of the application of monads, one day we’ll look back at this language as one of the most important in this book.
Haskell plays another role, too. The purity of the approach and the academic focus will both improve our understanding of programming. The best of the next generation of functional programmers in many places will cut their teeth on Haskell.
| [25] |
Star Trek: The Original Series, Episodes 41 and 42: “I, Mudd”/“The Trouble with Tribbles.” Directed by Marc Daniels. 1967; Burbank, CA: 20th CBS Paramount International Television, 2001. |
| [26] | |
| [27] | |
| [28] | |
| [29] |
http://moonbase.rydia.net/mental/writings/programming/monads-in-ruby/00introduction.html |