Describing Microservices using Modern Haskell
- by Alejandro Serrano
- July 31, 2020
- haskell• functional programming• functional• mu• microservices• rpc• grpc• protocol buffers• avro• graphql• academia
- 5 minutes to read.
We started a new project almost a year ago with a clear goal: create an idiomatic Haskell port of Mu, which, at that point, only targeted Scala. This posed a challenge: we aimed to bring all the lessons learned from creating this microservices library, while creating an experience in which any Haskeller would feel at home.
At this point in time, we have had three cool releases of Mu-Haskell, with a fourth one in the works. From our initial target of gRPC, we have expanded to GraphQL, allowing developers to expose different protocols from a single core logic.
It is no secret that Mu-Haskell uses several advanced features of the language in its core. We talked a bit about them in the Dutch Functional Programming Day 2020 and in one of 47 Degrees’ Show and Tell sessions. At some point, we were stretching the compiler as far as we could, and had to learn the limits of what was feasible (and sensible!) to do.
Developing Microservices in Modern Haskell describes those challenges in depth, especially those related to type level programming in Haskell. The goal is two-fold. First, we wanted to put in print some recurring patterns in type level programming, so they become better-known. Second, we aim to inform language designers about the struggles in using these new concepts.
Being where language designers meet
Programming Language Design is an interesting area of knowledge. Many people developing tools and techniques work in academia or have an academic background (like the author of this post), while, at the same time, new languages are often backed by the titans of the industry (think of Kotlin by Google, Swift by Apple, or TypeScript by Microsoft). This creates a virtuous cycle; for a few years, ideas stemming in academia have moved to mainstream usage at an increasingly faster pace. At 47 Degrees, we aim to be part of this process, creating better libraries and tools for everybody in the FP community, and making people aware of the new developments.
Still, there is a great division between conferences geared towards practitioners and those geared toward researchers, although some like Curry On are working hard to blur the line. In the case of functional programming, the conference by level of excellence is the International Conference of Functional Programming, where the best papers (lingo for “academic article”) are presented every year. Alongside this main event, a constellation of other smaller conferences are organized, usually targeting more specific topics. In our case, our paper was accepted for Haskell Symposium. Those are the places that have witnessed the birth of type families and data type promotion, among many other features of modern type level Haskell.
By the way, most Programming Language researchers are members of SIGPLAN, an interest group on the topic. This group organizes most of the academic conferences in the field. You can browse the most recent ones and download most of the presented papers. The talks are often available on YouTube.
A bit about those challenges
Most of the challenges we found during the development of Mu-Haskell stem from the combination of different features in type level programming. The core of Mu-Haskell, schema and service descriptions, makes heavy use of GADTs, data type promotion, type applications, multi-parameter type classes, and generics. In particular, the paper points to four specific challenges:
- Type applications (and
Proxytypes) provide an alien interface and lack good inference. We found that optics provide a better language, and we look forward to the inclusion of
RecordDotSyntaxin the language.
- GADTs provide a hard API for beginners, in particular when using heterogeneous lists. As a workaround, we provide a way to convert from the better-known tuples into the form required by Mu-Haskell.
- Type classes, which we often need to implement visitors over schemas and services, provide no abstraction or encapsulation mechanism. As a consequence, one often needs to carry around a huge amount of parameters, and ends up reimplementing common patterns like iteration over a list because there is no notion of
mapat the type level.
- Error messages suffer a lot, especially due to ambiguous type variables. This means that newcomers to the library have a hard time figuring out what went wrong where something breaks (and sometimes it’s as hard to detect as forgetting to enable one of the many GHC extensions.
If you are interested in knowing a bit more, I strongly encourage you to read the paper. It’s only 7 pages long. 😜
The development of Mu is proudly sponsored by 47 Degrees, a Functional Programming consultancy with a focus on the Scala, Kotlin, Swift, and Haskell programming languages. We offer a wide range of courses on those topics (including type level programming in Haskell!). We want to thank 47 Degrees for being completely supportive in our task of bridging the gap between industry and academia.