Direct-style effects, also known as algebraic effects and effect handlers, are the next big thing in programming languages. They are already available in Unison and OCaml, are coming to Scala, and I'm seeing discussion about them in other closely-related-to-industry contexts.
The goal is very simple: to allow us to write code in a natural style without monads, but still get the benefits of reasoning and composition that monads bring. At the same time I see some confusion about direct-style effects. In this post I want to address this confusion by explaining the what, the why, and the how of direct-style effects using a Scala 3 implementation as an example.
There is quite a bit going on here. First we'll talk about the problem we're trying to solve and the constraints we're operating under. Then we'll look at a simple implementation in Scala 3 and describe the language feature, contextual functions, that enables it. Next up we'll see some shortcomings of this implementation and see how they can solved by two language features, one well known (delimited continuations) and one in development (type system innovations). Finally I'll give some pointers to more about information on this topic.
For the next edition of Scala with Cats I'm writing a section on implementing interpreters. In my research I ended up going fairly deep down the rabbit hole of optimizations, in which virtual machine dispatch is a major area. There are many different approaches to dispatch, and I struggled to relate them until I realized they were all variations on a basic structure that resulted from applying the principle of duality. Duality is one of the major themes of the book, so I was happy to make this discovery. However I think going deep into optimization is not appropriate for the book so I'm writing this up here instead.
ScalaBridge London is a community for learning Scala, for people who are underrepresented in technology. We last met in 2020, stopping when COVID made it impossible to continue. I want to restart ScalaBridge London. Here's the plan. If you'd like to take part, please signup.
I'm rewriting my books to include new material and target Scala 3. I'm opening sponsors so you can encourage me to finish faster.
Function programming is based1; that is, based on principles that allow a systematic and repeatable process for creating software. In this post I'm going illustrate this process with an example of summing the elements of a list, inspired by this conversation. We'll mostly be looking at algebraic data types and structural recursion (which often uses pattern matching, but is not synonymous with it).
For me, a working functional programmer, this process is one of the main advantages of FP. It means I can spend my mental cycles on understanding the problem, knowing that once I have done so the implementation follows in a straightforward way. The inverse also holds: if someone uses these principles to write code I can easily work out what problem it solves.
In this article I'm going to go through the process of improving some code. I'm mentoring a new developer who is applying for their first job. They were asked to complete some tasks on Codility as the first step of the interview process. To get used to the platform they did the first example task, and I advised them on some changes. I'm writing up here the progression from their code to (what I think is) better code. (Since this is the example task, not a task used to assess applicants, I think this is ok to publically post.)
"I was three when the elephants ate the house next door," opens a paragraph on page 108 of my copy of Enough, the new book by Dr Cassandra Coburn. It encapsulates a lot of what I like about this book: it deals with important issues but it's also a lot of fun.
Building an understanding of code is one of the main tasks in software development. Whenever we want to answer a question about code—what is this doing? why doesn't it work? how can we make it faster?—this is what we're doing. I have found it valuable to consciously surface the strategy I use to answer these questions, and have categorized my approaches into three groups:
In this post I will discuss these different ways of understanding code and their benefits and drawbacks.
I recently led a training session where we implemented the rules for scoring ten-pin bowling in Scala. It makes for a good case study. It’s small enough that you can pick up the rules in a few minutes, but the dependencies between frames makes calculating the score non-trivial. I decided to implement my own solution which turned into an interesting exercise in algebraic data and finite state machines. In this post I'll describe my implementation and my process for developing it.
For my implementation I solely focused on scoring the game. I didn't implement any parsing code, as that part of the problem didn't interest me.
The programming world is moving towards functional programming (FP). More developers are using languages with an explicit bias towards FP, such as Scala and Haskell, while object-oriented (OO) languages and their communities adopt FP features and practices. (A striking example of the latter is the rise of Typescript and React in the Javascript community.) So what is FP and what does it mean to write code in a functional style? It's common to view functional programming as a collection of language features, such as first class functions, or to define it as a programming style using immutable data and pure functions. (Pure functions always return the same output given the same input.) This was my view when I started down the FP route, but I now believe the true goals of FP are enabling local reasoning and composition. Language features and programming style are in service of these goals. In this post I attempt to explain the meaning and value of local reasoning and composition.
Scala with Cats 2 is underway, with a fancy new website. Go and join the mailing list linked from the site if you want to keep up with the latest developments.
In preparation for a talk at NEScala I wrote this quick survey on the research on curriculum and pedagogy for teaching programming (curriculum means what we teach, and pedagogy is how we teach it). My goals are:
My survey is based on the published literature, but it's not a comprehensive document. I'm not an academic and I don't have the time (sadly) to read all the relevant literature. However I've linked to papers I found interesting or important so you can explore further if something grabs your interest. There is a lot of interesting research out there and the tiny bit I've read has made my teaching much better.
In a previous post I discussed the steps needed to compile a http4s web service to an executable with GraalVM Native Image.. It's natural to ask what tradeoffs are made by going this route instead of using the JVM. In this post I present several benchmark results I obtained comparing the Native Image executable to the running on the JVM. Read on to find out which comes out on top!
A recent project has involved serverless web services in Scala, which led me to investigate using GraalVM's Native Image tool to create native executables. In this blog post I describe the steps necessary to build a native executable from a simple http4s web service. There is also complete code accompanying this example.
A few weeks ago we wrapped up season two of ScalaBridge London. (For us, a "season" is an intensive series of meetings over a short period of time. Season two was six meetings in six weeks, but we might change this in future.) Here I want to reflect on what---in my opinion---were the good and bad parts of this season, and discuss what happens next.
I would like to measure the effectiveness of ScalaBridge London, but this raises some tricky questions. For example, what does it even mean for ScalaBridge to be effective? I'm not sure. I'm writing this largely as a way to organise my thoughts, and share with others who may be able to help.
In an earlier post I described our first run of ScalaBridge London. Now I want to turn to the future and talk about lessons learned and what we're planning for the next run. Some of these plans are more concrete than others. One of the great things about ScalaBridge is we're learning as we do it, and almost everything is subject to change.
ScalaBridge aims to increase diversity within the Scala community by providing training in Scala to traditionally under-represented groups. ScalaBridge London is, as the name suggests, the London chapter of ScalaBridge. A month or so ago we finished the first "season" of ScalaBridge London. Now is a good time to reflect on what we did and how it worked out.
Gatsby is a Javascript framework for building static sites. It has the pernicious effect of infecting the browser cache, and won't go away until you manually clear the cache or deploy a file that kills it. Here I describe the problem and the solution.
Type classes and records of functions are two very similar tools that are available in languages like Haskell, Scala, and Rust. Given the similarity the question arises of which we should use. In this blog post I discuss when I think one language mechanism should be preferred over the other.
I recently gave a talk on teaching Scala. I first gave the talk at the Scala in the City meetup, which was a dry run for the version I gave at Scala Days. Take a look at my slides if this is of interest to you. My talk centered around five tips for teaching. Here I give a quick rundown of the tips and some references for further reading.
How do you write an abstract for a (industry) conference talk proposal? I like to use a three paragraph structure. The first paragraph gives a quick overview of what attendees can expect to learn if they attend the talk. The second paragraph gives motivation and background—why should attendees care about what I have to say? The third and final paragraph goes into more detail on the points I intend to cover.
Last update: 15 February 2020
I recently switched to Doom Emacs from Spacemacs. The Doom documentation is currently quite sparse, so I've posted here my personal notes on using Doom along with a description of my workflow (something I find vital but missing from most documentation). Doom might be for you if
helm
; andI'm not going into detail on how Emacs works or basic Vim keybindings here---the focus is on the things I found different and useful.
I've just moved house---I'm now living near Cambridge---so it seems appropriate I should update my digital home as well.
This is a post about church and state, and how we can unite the two for a better world, while avoiding unfortunate side effects.
Political metaphors aside, this really is a post about Church—Alonzo Church—and how we can use his idea of Church encoding to unite pure FP and imperative OO to achieve, if not a better world, at least better code.
The interpreter is the über pattern of functional programming. Most large programs written in a functional style can be viewed as using this pattern. Amongst many reasons, interpreters allow us to handle effects and still keep desirable properties such as substitution.
Given the importance of interpreters it is not surprising there are many implementation strategies. In this blog post I want to discuss one of the main axes along which implementation strategies vary, which is how far we take reification of actions within the interpreter.
At the Typelevel Summit in Philadelphia I gave a talk about probabilistic programming, which I have recently been exploring. Probabilistic programming combines two great research areas that go great together---functional programming and machine learning (specifically, Bayesian inference). In this blog post I'll attempt to explain the basic ideas behind probabilistic programming. I'm assuming you, dear reader, skew more towards programming than statistics, but are not afraid of numbers. Hence I'll concentrate more on the programming than the machine learning side of things here.
I recently saw this image, taken from a maths test.
The student has been asked to represent 5×3 in terms of repeated addition. They have written 5+5+5. The teacher has marked this as incorrect and given 3+3+3+3+3 as the correct answer. Like many people, when I first saw this I thought the teacher was clearly wrong. After a bit of thought I realised they were correct, and after still more thought I realised this question raises a whole lot of interesting points.
So why isn't 3×5 the same as 5×3?
In a recent training course I was asked if Scala supports static or dynamic polymorphism. These are not terms I had heard before, so I had some homework to do. A bit of research showed this terminology refers to the same thing as early and late binding, which I'm more familiar with. So, here we have a quick discussion of early binding (or static polymorphism) and late binding (or dynamic polymorphism), and how it relates to Scala's polymorphic methods and overloading.
A major theme of this blog is design principles for Scala code. In the past we've talked about Scala mechanics like [sealed traits][sealed-traits] and general principles like [simplicity in Scala][keep-scala-simple]. In this post I want to discuss a very general principle called reification and show its application in two different domains: monad composition and stream libraries like Akka Stream.
I recently wrote about [keeping Scala simple][scala-simple]. That's something you have to work at. Let me explain.
While packing up to move house I came across my undergrad vector calculus notes. Although I, sadly, don't remember the definitions of div, grad, and curl I do remember that course as marking a turning point in my academic career.
In this post I want to explore the design of a type class solving a problem that came up repeatedly in my current project. It's fairly general, so rather than diving into the details of the project, I'll start with a few simple examples:
?.
operator in Kotlin and Coffeescript is annihilated by null
, in that once a null
is introduced the result is always null
.You don't have to venture far to find people arguing that Scala is a complex language, or that Scala needs to be more opinionated. Luckily I have plenty of opinions, specifically about how to make Scala simpler, and this is something I've been espousing in my recent talks at Scala Days SF and Amsterdam (slides here).
The problem with talking about simplicity is that it becomes one of those things like "good art" that's defined as "I know it when I see it." This provides no guidance. We need more precision. In this blog post I want to discuss complexity from three different angles and give concrete recommendations for creating simple Scala code.
You wouldn't think the Internet would need a an introduction to cats, but then this Cats is a Scala library, not a small furry bed-hogging mammal. Cats is the spiritual successor to Scalaz: a library of absolutely essential utilities you really want to be using in your Scala code. Compared to Scalaz, Cats is more modular and it is using some newer tools to make its code base easier to work with.
Cats is still a closer to being a kitten than the king of the alley, but it has definitely reached the stage where it is usable. In this article I'll provide a basic introduction to getting started with Cats.
My recent post on sealed traits had some great feedback but it was clear that I glossed over some points too quickly. In this post I want to go over a new trick I've learned for sealed traits and clear up some of the points I made in the last post.
Sealed traits are essential for idiomatic Scala code, but many developers are hazy on the details of their working. In this post we describe why you want to use them, and how to use them correctly to increase the quality of your code.
Understanding monads is a puzzle with many parts. Understanding the monad interface was easy enough for me, as I'd been programming in functional languages for a while when I first started exploring them, but for a long time I didn't understand how they made IO operations pure. The answer is to add an extra wrinkle, usually glossed over in Haskell oriented sources, by making all IO actions lazy. It this article we're going to explore how this works and undercover some surprising relationships to the free monad, which we have been covering in [recent][free-monad-interpreter] [posts][free-monad-deriving].
The free monad is defined by this structure1:
sealed trait Free[F[_], A]
final case class Return[F[_], A](a: A) extends Free[F, A]
final case class Suspend[F[_], A](s: F[Free[F, A]]) extends Free[F, A]
We can use the free monad without understanding its implementation, but to really understand it we need to know why it is defined this way.
It certainly wasn't obvious to me why this is the correct definition, and reading the literature quickly devolved into "doughnoids in the category of pretzelmorphisms" land. Here I want to present an explanation aimed at programmers that doesn't involve abstract alphabet-soup.
I recently gave a talk at the Advanced Scala meetup in London on free monads. Despite the name of the group, I think that free monads are eminently simple as well as being extremely useful. Let me explain.