10 Must-Have Haskell Libraries for Functional Programming
Haskell supports a broad range of libraries, which is why it’s such a good product to use. If you are headed down the path as a functional programmer, you should check out the rather lengthy list of available Haskell libraries. Chances are that you’ll find a Haskell library to meet almost any need in functional programming.
The problem is figuring out precisely which library to use and, unfortunately, the Hackage site doesn’t really help much. The associated short descriptions are generally enough to get you pointed in the right direction, but experimentation is the only real way to determine whether a library will meet your needs. In addition, you should seek online reviews of the various libraries before you begin using them. Of course, that’s part of the pleasure of development: discovering new tools to meet specific functional programming needs and then testing them yourself.
Haskell library #1: binary
To store certain kinds of data, you must be able to serialize it — that is, change it into a format that you can store on disk or transfer over a network to another machine. Serialization takes complex data structures and data objects and turns them into a series of bits that an application can later reconstitute into the original structure or object using deserialization. The point is that the data can’t travel in its original form. The binary library enables an application to serialize binary data of the sort used for all sorts of purposes, including both sound and graphics files. It works on lazy byte strings, which can provide a performance advantage as long as the byte strings are error free and the code is well behaved.
This particular library’s fast speed is why it’s so helpful for real-time binary data needs. According to the originator, you can perform serialization and deserialization tasks at speeds approaching 1 Gbps. According to the discussion at Superuser.com, a 1 Gb/sec data rate is more than sufficient to meet the 22 Mbps transfer rate requirement for 1080p video used for many purposes today. This transfer rate might not be good enough for 4K video data rates.
If you find that binary doesn’t quite meet your video or audio processing needs, you can also try the cereal library. It provides many of the same features as binary, but uses a different coding strategy (strict versus lazy execution). You can read a short discussion of the differences on Stack Overflow’s site.
Most of the libraries you use with Haskell will specify a GHC version. The version number tells you the requirements for the Haskell environment; the library won’t work with an older GHC version. In most cases, you want to keep your copy of Haskell current to ensure that the libraries you want to use will work with it. Also, note that many library descriptions will include support requirements in addition to the version number. Often, you must perform GHC upgrades to obtain the required support or import other libraries. Make sure to always understand the GHC requirements before using a library or assuming that the library isn’t working properly.
Haskell library #2: Hascore
The Hascore library gives you the means to describe music. You use this library to create, analyze, and manipulate music in various ways. An interesting aspect of this particular library is that it helps you see music in a new way. It also enables people who might not ordinarily be able to work with music express themselves. The site shows how the library makes lets you visualize music as a kind of math expression.
Of course, some musicians probably think that viewing music as a kind of math is to miss the point. However, you can find a wealth of sites that fully embrace the math in music, such as the American Mathematical Society (AMS) page. Some sites, such as Scientific American even express the idea that knowing music can help someone understand math better, too.
The point is that Hascore enables you to experience music in a new way through Haskell application programming. You can find other music and sound oriented libraries.
Haskell library #3: vect
Computer graphics in computers are based heavily in math. Haskell provides a wide variety of suitable math libraries for graphic manipulation, but vect represents one of the better choices because it’s relatively fast and doesn’t get mired in detail. Plus, you can find it used in existing applications such as the LambdaCube engine, which helps you to render advanced graphics on newer hardware.
If your main interest in a graphics library is to experiment with relatively simple output, vect does come with OpenGL support, including projective four-dimensional operations and quaternions. You must load the support separately, but the support is fully integrated into the library.
Haskell library #4: vector
All sorts of programming tasks revolve around the use of arrays. The immutable built-in list type is a linked-list configuration, which means that it can use memory inefficiently and not process data requests at a speed that will work for your application. In addition, you can’t pass a linked list to other languages, which may be a requirement when working in a graphics or other scenario in which high-speed interaction with other languages is a requirement. The vector library solves these and many other issues for which an array will work better than a linked list.
The vector library not only includes a wealth of features for managing data but also provides both mutable and immutable forms. Yes, using mutable data objects is the bane of functional programming, but sometimes you need to bend the rules a bit to process data fast enough to have it available when needed. Because of the nature of this particular library, you should see the need for eager execution (in place of the lazy execution that Haskell normally relies on) as essential. The use of eager processing also ensures that no potential for data loss exists and that cache issues are fewer.
Haskell library #5: aeson
Haskell library #6: attoparsec
Mixed-format data files can present problems. For example, an HTML page can contain both ASCII and binary data. The attoparsec library provides you with the means for parsing these complex data files and extracting the data you need from them. The actual performance of this particular library depends on how you write your parser and whether you use lazy evaluation. However, according to a number of sources, you should be able to achieve relatively high parsing speeds using this library.
One of the more interesting ways to use attoparsec is to parse log files. The article at School of Haskell discusses how to use the library for this particular task. The article also gives an example of what writing a parser involves. Before you decide to use this particular library, you should spend time with a few tutorials of this type to ensure that you understand the parser creation process.
Haskell library #7: bytestring
You use the bytestring library to interact with binary data, such as network packets. One of the best things about using bytestring is that it allows you to interact with the data using the same features as Haskell lists. Consequently, the learning curve is less steep than you might imagine and your code is easier to explain to others. The library is also optimized for high performance use, so it should meet any speed requirements for your application.
Unlike many other parts of Haskell, bytestring also enables you to interact with data in the manner you actually need. With this in mind, you can use one of two forms of bytestring calls:
- Strict: The library retains the data in one huge array, which may not use resources efficiently. However, this approach does let you to interact with other APIs and other languages. You can pass the binary data without concern that the data will appear fragmented to the recipient.
- Lazy: The library uses smaller strict arrays to hold the data. This approach uses resources more efficiently and can speed data transfers. You use the lazy approach when performing tasks such as streaming data online.
The bytestring library also provides support for a number of data presentations to make it easier to interact with the data in a convenient manner. In addition, you can mix binary and character data as needed. A Builder module also lets you easily create byte strings using simple concatenation.
Haskell library #8: stringsearch
Manipulating strings can be difficult, but you’re aided by the fact that the data you manipulate is in human-readable form for the most part. When it comes to byte strings, the patterns are significantly harder to see, and precision often becomes more critical because of the manner in which applications use byte strings. The stringsearch library enables you to perform the following tasks on byte strings quite quickly:
- Search for particular byte sequences
- Break the strings into pieces using specific markers
- Replace specific byte sequences with new sequences
This library will work with both strict and lazy byte strings. Consequently, it makes a good addition to libraries such as bytestring, which support both forms of bytestring calls. Learn more about how this library performs its various tasks.
Haskell library #9: text
There are times when the text-processing capabilities of Haskell leave a lot to be desired. The text library helps you to perform a wide range of tasks using text in various forms, including Unicode. You can encode or decode text as needed to meet the various Unicode Transformation Format (UTF) standards.
As helpful as it is to have a library for managing Unicode, the text library does a lot more with respect to text manipulation. For one thing, it can help you with internationalization issues, such as proper capitalization of words in strings.
This library also works with byte strings in both a strict and lazy manner. Providing this functionality means that the text library can help you in streaming situations to perform text conversions quickly.
Haskell library #10: moo
The moo library provides Genetic Algorithm (GA) functionality for Haskell. GA is often used to perform various kinds of optimizations and to solve search problems using techniques found in nature (natural selection). Yes, GA also helps in understanding physical or natural environments or objects, as you can see in the this tutorial. The point is that it relies on evolutionary theory, one of the tenets of Artificial Intelligence (AI). This library supports a number of GA variants out of the box:
- Binary using bit-strings:
- Binary and Gray encoding
- Point mutation
- One-point, two-point, and uniform crossover
- Continuous using a sequence of real values:
- Gaussian mutation
- BLX- α, UNDX, and SBX crossover
You can also create other variants through coding. These potential variants include
- Hybrid encodings, which would require customizations
The readme for this library tells you about other moo features and describes how they relate to the two out-of-the-box GA variants. Of course, the variants you code will have different features depending on your requirements. The single example provided with the readme shows how to minimize Beale’s function (check out the description of this function). You may be surprised at how few lines of code this particular example requires.