Are you ready to take a look beyond the surface of Haskell and really get the details of how things are implemented? Ready for a Haskell course that moves past the basics and focuses on the importance of performance and optimization - this course is for you!
It is a part of the beauty of Haskell that you typically do not have to think too hard about performance. You can write code in a concise and declarative way, and still have it perform fast. Sometimes, however, it pays off to know more about how programs run. Choosing the right data structure can make the difference between a program that runs instantaneous or one that runs forever. Making programs either too strict or too lazy can cause space leaks, which may not only result in too much memory being used, which can be very bad for long-running processes, but also result in more work for the garbage collector and make everything slower. In this course, you'll take a look beyond the surface of Haskell and at how things are implemented. You'll discuss the internal representation of data on the heap, what exactly lazy evaluation means and how it works, how the compiler translates Haskell code to a target language via several internal representations, and what you can and cannot reasonably expect the compiler to do, and how you can tweak the optimizer behaviour by using compiler pragmas such as inlining annotations and rewrite rules. For all the low-level concept discussions will keep track of the high-level goals: to wrap certain performance-critical parts of the code under a high-level interface, so that you do not need to expose ugly details on the surface, but can write beautiful programs that scale. For this, the course will look at existing widely used and highly optimized libraries and take a look at how they are implemented internally. The course will also work through several carefully crafted hands-on exercises and examples to deepen the understanding of the concepts discussed and to illustrate common pitfalls and corner cases.
Learn how to:
- Understand common Haskell data structures and their performance characteristics.
- How to avoid common performance pitfalls.
- Understand how custom rewrite rules work.
- Use interesting optimizations such as lambda lifting, (stream) fusion and worker-wrapper.
Common Haskell data structures and their performance characteristics, such as lists, sequences, finite maps, hash maps, byte strings, text and arrays.
Unboxed types and the tradeoffs between boxed and unboxed types.
Lambda calculus and evaluation strategies; the differences between call-by-value, call-by-name and call-by-need (lazy evaluation).
GHC's compilation process and its intermediate languages: Core, STG and C--, with an emphasis on understanding Core.
Strictness analysis and space leaks.
Common performance pitfalls and how to avoid them.
Debugging tools such as time and space profiling.
How the inliner works and how it can be tweaked. How custom rewrite rules work.
Some interesting optimizations such as lambda lifting, (stream) fusion and worker-wrapper.
This course targets Haskell developers who have a solid understanding of basic Haskell concepts and want to write large(r) Haskell programs that scale. In terms of language concepts, knowing the contents of "Well-Typed's Fast Track to Haskell" is sufficient, and the two courses can in principle be taken back to back. In practice, the benefit of this course will be higher if participants have already gained some experience writing Haskell code on their own.
Bring your own hardware
You are expected to bring your own laptop with your preferred IDE.