Book Chat: Functional Programming in Scala

I had been meaning to get a copy of this for a while, then I saw one of the authors, Rúnar Bjarnason, at NEScala 2017 giving a talk on adjunctions. Before seeing this talk I had been trying to wrap my head around a lot of the Category Theory underpinning functional programming, and I thought I had been making progress. Seeing the talk made me recognize two facts. First, there was a long way for me togo. Second, there were a lot of other people who also only sort of got it and were all there working at understanding the material. At the associated unconference he gave a second talk which was much more accessible than the linked one. Sadly there is no recording, but I started to really feel like I got it. Talking with some of the other attendees at the conference they all talked about Functional Programming in Scala in an awe inspiring tone about how it helped them really get functional programming, and the associated category theory.

The book is accessible to someone with minimal background in this, so I came in a somewhat overqualified for the first part but settled in nicely for the remaining three parts. It’s not a textbook, but it does come with a variety of exercises and an associated repo with stubs for the questions and answers to the exercises. There is also a companion pdf with chapter notes and hints about how to approach some of the exercises that can help you get moving in the right direction if stuck.

Doing all of the exercises while reading the book is time consuming. Sometimes I would go read about a half a page and do the associated exercises and spend more than an hour at it. The entire exercise was mentally stimulating regardless of the time I committed to the exercise, but it was draining. Some of the exercises were even converted to have a web-based format that is more like unit testing at Scala Exercises.

I made sure I finished the book before going back to NEScala this year. Rúnar was there again, and gave more or less the same category theory talk as the year before, but this time around I got most of what was going on in the first half of the talk. In fact, I was so pleased with myself, that I missed a key point in the middle when I realized how much of the talk I was successfully following. I ended up talking with one of the organizers who indicated he encouraged Runar to give this same talk every year since it is so helpful to get everyone an understanding of the theoretical underpinnings of why all this works.

This book finally got me to understand the underlying ideas of how this works as I built the infrastructure for principled functional programming. It leaned into the complexity and worked through it whereas other books (like Functional Programming in Java) tried to avoid the complexity and focus on the what not the why. This was the single best thing I did to learn this information.

Advertisements

NEScala 2018

I attended NEScala 2018 recently for the second time and wanted to discuss the experiences I had there. It’s three loosely affiliated conferences across three different days. The first day was an unconference, the second was NEScala proper, and the third day was a Typelevel summit. I saw a bunch of great talks and met other practitioners who all brought a different perspective to the same sorts of problems I work with every day, as well as some people who have radically different problems.

There were a pair of talks from presenters at Twitter on how they deal with their monorepo using Scalafix and Pants. These were interesting solutions to the problems of the monorepo. During the transition to the microservices at my current job the code base has shattered into hundreds of repositories, which comes with problems, and you sometimes look and wonder if doing this another way would solve those problems. This was a clear reminder that there are problems on the other side that are just as difficult – just different.

The sections on Http4s(talk) and sttp were especially interesting to see the way they tackled HTTP servers and clients as purely functional structures. HTTP was in my mind difficult to describe purely functionally because it is all about referentially untransparent actions. Sttp was especially interesting because we had built a similar abstraction at work in the last year and seeing how others made different tradeoffs was interesting.

The big takeaway for me was that functional programming purity is a pragmatic thing. Functional programming is a tool to tackle complexity in software, but it’s not the only tool available to do that. There are ways to use local effects to wrap small bits of imperative code, but outside of the function where the imperative code lives, none of the callers can tell. You have a thin imperative wrapper on the outside and possibly little imperative nuggets on the inside that resolve performance issues and occasionally improve algorithmic readability, but the whole program retains the composability and readability of an immutable program.

Monads for the Working Programmer

The monad is a backbone of functional programming. However, the mathematical definition of what a monad is highly inaccessible. I want to try and describe a monad for a programmer who is new to functional programming. This isn’t intended to be a precise definition, it is intended to be enough to help understand what the monad is, how to use it, and why it’s a helpful construct.

Consider the monad as a box. The box can be empty and the box doesn’t really care what’s in it. You can go get a box and put something in it. Someone can open up the box, take out what’s in there, work with it, then put their output back in the box. That’s really all there is to it.

Sometimes the box is less tangible than other boxes. For instance, Future in Scala or IO in Haskell don’t have an actual value yet, but the promise of a value later. Think of it like a package in the mail, the box may not be here yet but you can make plans for when it gets to you. You can plan to open the box and combine it with another value you have and put it back in the box. In programming terms it’s a continuation, you take the first box and attach some code to it so that when the value in the box does show up you run the continuation with it.

Sometime the box is a bit bigger than others, like the List monad. The List monad has more than one thing in the box like an egg carton, but they’re all of the same type. You can still open up the box and take out an egg and do something with it, or you can process each of the eggs in turn.

When you want to use a monad it’s as easy as that – your functions all start wrapping their return types in that monad. Their callers then open the box and do their work and return the new value to the box. So instead of pseudo code that looks like


values = [3, 4, 5]

for(int i =0; i<span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>< values.length; i++) {

	values[i] = values[i] * 2;

}

 

 

You get pseudo code that looks like


values = [3, 4, 5]

doubled = values.map(value => value * 2)

But what’s the point of this programming style, what does it get you? First, it helps you work with immutable data. In the first example above you are mutating whatever values is. That’s fine in object oriented or procedural programming, but functional programming sacrificed mutable data for thread safe composability. Second, it produces code that is easily composable. If I wanted to subtract one before doubling the values in the above monad example, I could add another map statement entirely, separating the two concerns. In the initial example the two concerns would be mixed into the same control flow. Third, the monad itself can contain a fair bit of logic to enrich the programming experience. The ability to interact with a Future, an Option, a List, or any other monad in the same way simplifies a lot of refactorings. If you want to replace an Option with a List application logic doesn’t need to change much. Hopefully all of this helps demystify the Monad and helps you to write better code.