BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage Articles Functional Programming in Scala Review and Q&A with the Authors

Functional Programming in Scala Review and Q&A with the Authors

Bookmarks

Paul Chiusano and Rúnar Bjarnason's Functional Programming in Scala "is not a book about Scala," say the authors, rather it is a principled introduction to functional programming that relies on Scala. As such, the book does not delve much into Scala syntax or semantics and moves quickly through basic functional programming concepts to get to more advanced and abstract notions.

The main appeal of the book resides in its attempt to present advanced and even complex functional programming concepts through a series of progressively more complex and carefully thought out exercises aimed to help the reader gain a better grasp of them.

The book is comprised of our parts.

The first part focuses on fundamental concepts and techniques used in functional programming, such as referential transparency, purity, laziness, functional data structures, etc.

The second part of the book focuses on functional design and guides the reader through the overall design process for a few libraries aimed to solve problems such as creating parallel and asynchronous tasks, property-based testing, and parsing. Instead of presenting their case-study designs, the authors show how to approach the problem of designing a purely functional library that is highly composable and modular. In particular, they emphasize the notion of algebraic design and introduce the powerful idea that an API can be described by an algebra that obeys specific laws. This way, by simply doing formal symbol manipulation following those laws, it becomes possible to prove properties of the API.

The third part introduces higher abstractions that allow to reason about the code and can be very powerful when designing libraries. This leads the authors to describe purely algebraic structures such as monoids, monads, and applicative functors in a generic way, as algebraic structure that represents properties common to many different data structures or APIs.

Finally, part 4 deals with I/O and gives examples of real world applications that accesses databases, files, or video display by relying on the concepts developed in previous chapters.

InfoQ has taken the chance of this review to ask the authors a few questions and learn more about their intent with the book.

InfoQ: Could you explain what was the motivation to write this book?

Rúnar: Paul and I worked together at Capital IQ on a small team using functional programming with excellent results, and we were both pretty active in the Scala community in Boston. We decided to run a weekly meeting at work, where we would teach FP concepts to our coworkers using Scala. The format we used relied heavily on exercises, and it worked really well. At the time there were no books on FP in Scala, or even any online resources that we could use, so we had to make all of our own material. When our friend Nermin from the Boston Scala meetup suggested that we write a book on the subject, we already had a pretty good idea of the kind of book we wanted to write.

InfoQ: In the intro to the book you state clearly that your book is not about Scala, rather it is an introduction to FP. Could you explain the reasons that led you to choose Scala instead of another functional language?

Rúnar: Well, there was no good material out there already about doing FP in Scala. So we really wanted to bridge that gap. But more than that, we wanted to present FP in a very explicit way. The fact that Scala is not a purely functional language is an important motivational device for the material in the book. In a purely functional language, the question of whether to do something in a functional way or by resorting to side effects simply never comes up. We want to emphasize the value of functional techniques no matter the language. FP is quite natural in Scala, but you have to make a conscious choice to use it. That makes it a good language to teach these concepts in.

Paul: Yes, in Scala, we can't just accept it as a forgone conclusion why something must be done without side effects, we actually have to motivate it! Especially in part 1, we really try to make the connection clear--many of the chapters start with a problem that we expect people already "know" how to solve using side effects, and we show how to accomplish the same thing purely functionally.

Scala is not very "opinionated" about what style of programming to use. You can write low-level imperative code or purely functional code, and everything in between. I think this versatility is part of why its become widely adopted on the JVM--aside from some new syntax, there is very little that a Java programmer absolutely must learn up front to become productive with Scala, and many people start out using it as "Java without semicolons". But while Scala has a nice, gradual adoption story, because it's not opinionated, developers new to Scala tend to fall back on using what they are comfortable with, which often means relying on side effects. A lot of people in this position are interested in going further with the FP side of Scala but lack a good avenue to do so. We really wanted to have a cohesive, complete narrative for developers in this position who were interested in taking greater advantage of Scala's support for FP.

InfoQ: What makes your book different from other books focusing on functional programming?

Rúnar: The main difference is that our book focuses on doing rather than telling. The concepts are explained in plain English, but the only way to really internalize them is to spend time applying them to actual programming, thinking about them, and playing with them. We try to emphasise the importance of exploration and play, both when learning and working.

Paul: We definitely spent a lot of time on developing the exercises used in the book. The exercises are simple enough to be self-contained, but also substantial enough to help the reader grok the material. Learning FP is not just about acquiring new knowledge or learning some syntax, there are new ways of thinking and different skills to learn, and the only way to develop these things is with practice. We want the book to be a good resource for getting this practice.

I also think part 2 of the book is rather unique in that we try to provide a window into the process of functional design. So we don't just dump a beautiful, fully formed functional library onto the reader's lap, we try to show at least a stylized view of the messy process of getting there. When you're teaching any subject, it's really easy to get into the mode where you only present the learners with the "finished product". Of course, the finished product looks great, but the learner is left scratching their head about how they'd ever come up with something similar on their own.

InfoQ: How would you describe the reasons for a developer to want to learn functional programming?

Paul: Well, on the one hand, there's this very practical argument that FP is slowly but surely taking over the industry. It's not just a fad; FP is a "great idea whose time has come" and is growing in popularity in part because of its very tangible benefits. So that's the practical argument. But was that why I learned FP? Not really, I wasn't so intentional about it. I just found the subject beautiful, fascinating, and fun, explored my own curiosity, and the benefits became increasingly clear as I gained more experience.

Rúnar: Yes, I think most of all, FP makes programming more fun and easy. Programming is already the most enjoyable work I can imagine, and FP amplifies that enjoyment tremendously. My code is more testable and reusable, and concurrency becomes straightforward. Also, functional programs are compositional, like Lego bricks, so they fit together in obvious ways. But they can also be taken apart any way you like.

InfoQ: In your book you cover the very foundations of functional programming introducing concepts such as referential transparency, the substitution model, purity, laziness, and so on. Then you move to more advanced topics such as algebraic properties of APIs, and powerful abstractions such monoids, monads, and applicative functors. This is a lot of ground and a somewhat daunting learning task. What approach you try to suggest for the reader to master such complexity?

Rúnar: I wouldn't say that there's a lot of complexity. FP is really a simplifying assumption, and the later parts of the book are just applications of the underlying principles that we introduce early on. Ultimately the message of the book is that any program can be constructed from just one kind of thing: pure functions operating on immutable data. That said, there is a lot of material to cover, and it goes quite deep. So we recommend taking it slowly. The book is split into 4 parts, and we think it's a good idea to take a break between parts to really play around with the ideas that you've learned and apply them in some actual software projects. Some people will also benefit from doing the exercises with other people. Start a book club at work, or join a local (or online) user group.

Paul: Yes, I very much agree FP actually makes programming simpler. There are fewer things to think about and fewer ways your programs can go wrong. It may be hard to see this without having experience in FP, but writing correct code with side effects is actually quite difficult! But actually, I don't like the way you've phrased your question. Learning about a deep, interesting, and extremely useful subject is something to be excited about. It's the start of a wonderful journey—calling it a "daunting task" makes it sound like an obligatory chore, like preparing one's taxes or filling out RMV forms! Yes, there are many new things to learn in FP, but if you just take it at your own pace, keep a "beginner's mind," and treat the learning itself as a fun adventure, you'll be successful.

InfoQ: One of the most powerful concepts that you explain in you book is that of algebraic data types and algebraic properties of APIs. Could you explain in which way they can change the way to write code?

Rúnar: A central theme in functional programming is compositionality. We construct both programs and data from a small set of primitives, with certain laws telling us how things compose to form larger things. We call a set of primitives together with some laws, collectively, an algebra. Algebraic data types simplify our code, particularly in that our functions need only know how to deconstruct the data type into its constituent parts. Since no side effects are allowed, there is never any out-of-band knowledge necessary to implement a function. We simply proceed to deconstruct its input. At a higher level, we design entire systems and APIs using the same principle.

Paul: I like to say that "code is meant to be abstracted over." That is, any piece of code we write should be something that we can treat as a black box and embed inside a larger box. We absolutely need this to manage the complexity of software. And algebraic properties are important because they facilitate "non-leaky" abstraction. When we abstract over a collection of values and functions related by laws, we can reason about what our larger black box means. That is, the algebra helps us build components that form a new semantic level rather than being something we must always unpack and understand in terms of constituent parts.

InfoQ: Could you summarize the importance of monads in functional programming? Monads are usually associated with I/O, side effects, or imperative programming inside, yet you present them in a broader perspective.

Rúnar: It's a common misunderstanding that monads are somehow tied to I/O or side effects. But a monad is just a particular kind of algebraic structure that we can exploit when designing our APIs. In the book, we talk about a lot of different things that have monadic structure: from ordinary lists and functions, to error handling, state machines, random number generators, parsers, futures, imperative I/O, mutable memory cells, and more. It's really interesting that these things all have a certain portion of their API in common, and in the book we talk about how to take advantage of this fact. The importance of monads is mainly that they are really common. So the code we write and the thoughts we think, once for all of them, are highly reusable.

InfoQ: What are the most basic concepts of functional programming that one should really get a good grasp of before moving on? Are there a few ground-laying concepts that should deserve more attention?

Rúnar: There are of course some basic concepts that are important to know, but there's no point at which you've learned enough to sort of "gain permission" to start doing FP. Just do it at the level you are at right now, to the extent that you are comfortable with. The book lays out some abstract concepts like referential transparency, functors, and monads. But we also made the book full of exercises to help with the most important thing, which is to get a lot of practice and really integrate FP into your work.

Paul: Beyond just knowing what side effects are, and understanding that FP means programming without side effects, there's no concept that I'd really single out. What I do think is important for learning FP is having a certain mindset, that you will try expressing programs you write without using side effects, and not be deterred if this seems awkward at first. That is, I think there are two attitudes you can take when expressing a program without side effects and encounter difficulty doing so. You can say "Oh noes! This is getting really brain-bending, FP is just too complex and not the right approach here." Or you can say "Hmm! I can't really think of a nice way of doing this functionally. What a great learning opportunity, though! I can't be the first functional programmer to have encountered this problem, I'll bet there's some nice way of doing it that I haven't thought of." Obviously, if you adopt the latter perspective, you'll make great progress in learning, and over time, expressing programs functionally becomes effortless.

InfoQ: Functional programming is often predicated to allow significant gains both in term of lines of code and development time. Which of the ideas and approaches that you present in your book are more likely to bring such gains?

Rúnar: It's my experience that FP really does reduce the amount of code I need to write. This is because FP helps get rid of a lot of complexity, and also grants a lot of code reuse. You could even say that FP is just a process of principled removal of duplication in your code. The third part of the book, "Common structures in functional design", is really the part where such gains are had. The fact that these structures are common means that we can write code that can be reused wherever they appear.

Paul: I do think that the structures covered in part 3 are a really clear demonstration of FP achieving code reuse in a way that's new to people, and which clearly solves a code duplication problem. But we see the same benefits at every level. Even the functions map, filter, and fold on lists are removing code duplication - rather than writing out loops manually every time we want to process a list, we assemble these loops from generic functions. If we ever notice ourselves repeating a certain pattern over and over, we can easily abstract that into a nice, generic function. And we apply the same sort of principled removal of duplication for all code that we write, regardless of whether it's code for working with lists or code that abstracts over several different functional libraries.

Another thing that doesn't get brought up enough is that functional code is extremely easy to test, usually much more so than code that relies on side effects. Lack of testability is a huge productivity drain, and people don't always realize just how much time they are spending working around the fact that large swaths of their code aren't easily testable. Finding and extracting the pure functions that might be buried inside a large application that uses side effects everywhere can bring huge increases in testability, with all the productivity benefits that come with that.

InfoQ: What is the most difficult aspect of  learning advanced  functional programming as you suggest in your book? And what could help, outside of practice, to master it? How important is math in trying to understand the subjects you cover?

Rúnar: I can really only speak from my own experience with learning these things. My background is in enterprise Java programming. FP is a really different way of thinking so the change of mindset is probably the hardest part. You have to keep a beginner's mind, and be unafraid to venture into territory where you don't understand anything at first. I've had no formal training in mathematics, so I can't say if that might make things easier. It's true that a lot of FP concepts come from mathematics, but they're the kinds of things you can really learn as you go, whenever you're ready or curious.

Paul: I'd mostly echo what Rúnar said. I do think a mathematics background can help, especially because mathematics can get you comfortable with abstraction in general, which is really important in FP, and the mode of thinking one uses when constructing proofs in mathematics is very similar to the sort of thinking one does when assembling functional programs. But I don't see mathematics as a prerequisite. You can definitely learn just things as you go, and that can be better anyway because you then learn in context.

In terms of the "FP curriculum", for me, there have been lots of little brain-bending ideas which, in retrospect, now seem straightforward. I don't think this is really specific to FP though, any deep subject or discipline with a lot of ideas in it will be like this as you learn it. Again, I think one's attitude toward learning is really critical--if you treat these little brain bending moments as exciting opportunities to learn something new and interesting, then it doesn't feel like work.

That said, I think something that can be difficult is how to handle getting stuck in understanding something. Sometimes, you just can't puzzle through things on your own, with the learning resources or the community you have access to, or maybe you could but you find yourself getting frustrated or uninterested. I think forming and participating in learning communities can really help here, whether it's a group at work or a local meetup. Something else that's always really helped me even when learning on my own is keeping the learning low stakes. That is, I try not to make understanding something new critical path for a feature at work that has a hard deadline. Instead, I give myself the freedom to tinker, leave things alone for a while if I want, and understand them at my own pace when I feel motivated and interested and it feels fun. Investing some amount of time in this is something I enjoy, and it pays dividends when you're able to put that new knowledge into practice.

You can order Functional Programming in Scala (all formats) at manning.com with 40% off. The code is fpsinfoq.

About the Book Authors

Rúnar Bjarnason is a software engineer in Boston, and one of two authors of Functional Programming in Scala. He has done diverse programming work for the past two decades, including software for agriculture, genomics, computer security, real estate, IT, finance, and media.

 

Paul Chiusano(@pchiusano) lives in Cambridge, MA and works as a freelance software consultant specializing in Scala and functional programming. He also contributes to several open source Scala libraries and blogs regularly about FP at pchiusano.io.

 

 

 

Rate this Article

Adoption
Style

BT