Afterword. What’s next?

Undoubtedly, the greatest challenge in writing a Haskell book is determining the scope. The most wonderful and simultaneously terrifying part of Haskell is its seemingly unlimited number of topics to learn. Unfortunately, it’s impossible to write a Haskell book without feeling that you’ve left out a great deal of interesting content.

The goal of this book has always been to provide a foundation for a solid understanding of both Haskell and functional programming in general. The good news is that if you’ve reached this point in the book, you have many options for taking your journey further. Even if you stop here, I’m confident that your view of software, programming, and computation in general has been expanded quite a bit. If you’re interested in pursuing the topics in this book further, this afterword provides a few options of where to go next, depending on which direction interests you the most.

A deeper dive into Haskell

If you enjoyed unit 5 on Functor, Applicative, and Monad, the good news is that those topics are the tip of the Haskell iceberg. Many other type classes and topics in Haskell offer similar levels of interesting abstraction and new ways to think about programs. The best place to continue this is on the Typeclassopedia, which is part of the Haskell wiki (found at https://wiki.haskell.org/Typeclassopedia). One of the primary goals of this book is to equip you with a solid-enough understanding of Haskell’s more abstract type classes that you could explore them on your own. The Typeclassopedia starts with the interesting type classes discussed in this book and then moves on to increasingly more powerful and abstract type classes.

One topic that we were unable to cover in this book is parallel and concurrent programming in Haskell. If you’ve done any work with parallel programming in a language such as C++, you know how tricky it can be to make sure state is maintained effectively when you have asynchronous computations being called. A major benefit of Haskell’s obsession with pure functional programming is that it’s much easier to parallelize Haskell code. A fantastic book by Simon Marlow, Parallel and Concurrent Programming in Haskell (O’Reilly Media, 2013), gives this topic the full coverage it deserves. Having completed this book, you should be able to easily jump in. Marlow’s book is free to read online: http://chimera.labs.oreilly.com/books/1230000000929/index.html.

The biggest change in Haskell since I first learned the language is the amount of headway it has gained in becoming a “real” programming language. A growing number of software engineers are writing production code with Haskell. The stack build system, which is a relatively recent addition to Haskell, is evidence of this. A good place to start exploring packages and libraries for Haskell is on the Haskell-lang.org libraries page (https://haskell-lang.org/libraries). This page covers many of the essential packages and tools you can use for writing Haskell programs (and we’ve touched on many in this book).

More powerful type systems than Haskell?

If Haskell’s powerful type system is what intrigued you the most about Haskell, you’ll be happy to know that a few languages out there, based on Haskell, try to push the type envelope even further. Two interesting examples are Idris and Liquid Haskell. Both languages expand on Haskell’s types by allowing even more detailed and powerful constraints on the types used in a program. Imagine if the compiler was able to warn you that head was a partial function, or you were able to specify the size of a list in your types. Both of these checks are beyond the power of Haskell’s type system, but are possible in Liquid Haskell and Idris.

Idris—programming with dependent types

Idris is a programming language that allows for dependent types. Idris has first-class types in the same way Haskell has first-class functions, so types can be computed and manipulated in Idris the same way that you manipulate functions in Haskell. What sort of power does this provide? One of the problems in Haskell related to foldl is that although foldl is often more intuitive than foldr, foldl doesn’t work on infinite lists. This, incidentally, makes foldl a partial function because you can’t check whether a list is infinite, and infinite lists are a value the function is undefined on. You could solve this problem if you could guarantee that your lists were finite. This is beyond the power of Haskell’s type system, but Idris’s dependent types make it possible to specify that a list argument must be finite.

You can learn more about Idris by visiting the language’s homepage (www.idris-lang.org/documentation/). Additionally, Manning has published a book on Idris by the creator of the language: Type-Driven Development with Idris by Edwin Brady (2017).

Liquid Haskell—provable types

Liquid Haskell expands on Haskell’s type system by allowing you to use logical predicates with your types to ensure proper program behavior. These types are called refinement types. Like Idris, Liquid Haskell’s type system works to eliminate partial functions through the type system. The constraints assumed on a program are checked at compile time. One example is that Liquid Haskell makes it possible to ensure that division by zero isn’t possible at the type level. The amazing thing about this is that division by zero errors can be caught when your code compiles. The best place to learn more about Liquid Haskell is on the project’s homepage (https://ucsd-progsys.github.io/liquidhaskell-blog/).

Other functional programming languages

Perhaps after reading through this book you’ve developed a love for functional programming but aren’t quite sure that Haskell is the best language for you. There are a wide variety of mature, powerful functional programming languages that you can explore. Haskell is certainly the purest of these languages, but that can sometimes be a downside.

Functional programming languages broadly fall into two families: the Lisp family and the ML family. Haskell is a good representation of the ML type of functional programming languages, which usually use a similar type system (though each type system has its own unique features). The Lisp languages are generally dynamically typed and involve heavy use of parentheses and prefix operators. If you’re interested in functional programming, I strongly recommend mastering both a Lisp family language and an ML family language. Although they share many commonalities, they’re both different ways to think about programs.

Recommended programming languages in the Lisp family

The biggest shock to most newcomers to any Lisp language is the abundance of parentheses. Lisp represents all programs as trees of computation, and nested parentheses are a good way to represent these trees. The tree structure allows for sophisticated manipulation of programs as data. A hallmark of many Lisp languages is the idea of macros, which allows for the generation of code at compile type. This allows Lisp programmers to easily define their own syntax when necessary. Writing a custom domain-specific language (DSL) in a Lisp can often require just a few lines of code. The following are a couple of good options for exploring Lisp in greater depth.

Racket

The Racket programming language is the descendant of a long line of languages from the Scheme dialect of Lisp. It’s probably the purest contemporary representation of the Lisp family and has amazing community support. Like Haskell, Racket has a relatively small commercial community compared to those who use the language to explore programming language theory. Despite its academic tendencies, the Racket community has done a great job making it easy to get started and learn Racket. You can learn more at the Racket website: https://racket-lang.org/.

Clojure

The Clojure programming language is by far the most commercially viable Lisp. Clojure sits on top of the Java Virtual Machine (JVM) and therefore has access to all Java libraries. A large community of practically minded, working software developers are using Clojure. If Lisp sounds interesting to you, but your primary interest is shipping code and getting things done, you’ll be happy with the Clojure community. More information can be found on the Clojure page: https://clojure.org/.

Common Lisp

Although Common Lisp is unfortunately rather dated at this point, it’s one of the most powerful programming languages ever created. Common Lisp is a language obsessed with abstracting out code as much as possible and creating, in my opinion, the most expressive programming language to date. The major downside is that it’s difficult to use Common Lisp for practical applications today. If you study this language in depth, you’ll fall tragically in love with it. A great intro to the language is Peter Seibel’s Practical Common Lisp (Apress, 2005), which is available free online: www.gigamonkeys.com/book/.

Recommended programming languages in the ML family

Haskell belongs to the ML family of functional programming languages. The greatest defining features of ML languages are their powerful type systems. Haskell is arguably the most challenging of the ML family because of its combination of using lazy evaluation, enforcing pure functional programming, and relying heavily on abstract concepts such as monads. If you like most of what you learned in the book but feel that Haskell is just a bit too challenging to work with, you might find your new favorite language in this group. The ML family typically includes many languages that are as academic as Haskell, such as Miranda and Standard ML. I’ve excluded these in favor of the following more pragmatic alternatives.

F#

The F# programming language is an implementation of another ML variant (OCaml) for Microsoft’s .NET programming environment. F# is a multiparadigm programming language with strong support for functional programming, as well as for object-oriented programming. If you’re a .NET developer using a language such as C#, you’ll likely find F# to be a great way to combine many of the things you enjoy about Haskell with the .NET ecosystem. Supported by Microsoft, F# has great documentation and a large variety of existing libraries and tools that will allow you to get a lot of practical work done. More can be learned from the F# homepage: http://fsharp.org/.

Scala

Like F#, Scala combines strong types, functional programming, and object-oriented programming. Scala runs on top of the JVM, and like Clojure, can readily make use of the vast number of libraries supported by that environment. Scala is a remarkably flexible language that allows you to write everything, from a less verbose form of Java, to code using monads and functors. Scala has a great community of developers and is probably your best bet if you’d like to do functional programming for a living. The tools and resources available for Scala are on par with any other industrial-strength programming language. You can learn more at the Scala site: www.scala-lang.org.

Elm and PureScript

Elm (http://elm-lang.org/) and PureScript (www.purescript.org) are distinct programming languages that offer the same goal: creating a language resembling Haskell that can be compiled to JavaScript. The Elm programming language is focused on creating JavaScript user interfaces using functional programming. The Elm website has a wide variety of great examples to get you started. PureScript (not to be confused with TypeScript) is focused on making a Haskell-like language that compiles to JavaScript. PureScript is similar to Haskell in syntax and usage and should be fairly easy to get started with, now that you’ve completed this book.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.105.227