Hi! I’m Zainab. I write relaxed tutorials on
functional programming, and present on all sorts of
intriguing topics. You can see what I’m up to on LinkedIn.
Flip open your laptop, grab a cup of tea and choose a talk below.
Reasoning through concurrent systems has always been a challenging
task. Poor code can be riddled with race conditions, non-terminating
cases and other complex concurrency bugs; and even well-written code
can be hard to understand. Async programming is an innovative
concurrent programming model that rises to this challenge. In this
talk, we'll explore reasoning with async Rust. We'll be introduced to
its fundamental building blocks, such as async, await, join and select, and learn how to predict the behavior of code written with them. We'll build on these to simplify more complex concurrency puzzlers. Finally, we'll explore different approaches to handling concurrent state and see how they compare.
The Currents of Concurrency: Reasoning with Async Rust
Reasoning through concurrent systems has always been a challenging
task. Poor code can be riddled with race conditions, non-terminating
cases and other complex concurrency bugs; and even well-written code
can be hard to understand. Async programming is an innovative
concurrent programming model that rises to this challenge. In this
talk, we'll explore reasoning with async Rust. We'll be introduced to
its fundamental building blocks, such as async, await, join and select, and learn how to predict the behavior of code written with them. We'll build on these to simplify more complex concurrency puzzlers. Finally, we'll explore different approaches to handling concurrent state and see how they compare.
In this session, we'll get to the heart of functional programming. We'll explore what it is, how to structure code with it, and how it benefits us when reasoning. We'll see how Rust's language features lend itself to developing in functional style.
Designing concurrent systems is challenging. It ought to be simple to
tell our programs do multiple things at once, but whenever we do so
our code is cumbersome to work with. Does it have to be?
In this talk, we explore the challenges of concurrent systems. We
look at the problems that arise when running multiple concurrent
tasks: the complexities of mutable state, resource manipulation, error
handling and interruption.
After taking a birds-eye view of different models of concurrent
execution, we'll have a deeper look at asynchronous programming on the
JVM. We will see how virtual threads are equipped to solve our
concurrency challenges, explore their benefits and drawbacks, and see
what lies ahead in the concurrency landscape.
The Currents of Concurrency: Reasoning with Async Rust
Pure functional programming is a powerful tool. With purity, we can
reason through complex code by breaking it up into small composable
parts.
But there are some areas that, despite being pure and functional,
still puzzle us. In this talk, we’ll navigate the challenging currents
of functional streams.
Beginning with basic pure functional programs, we’ll explore
effects with cats-effect and concurrency with fs2. Along the way,
we’ll encounter different frameworks for reasoning through code and
build our own mental model of stream evaluation. We’ll see that
functional streams, while inherently complex, are not as murky as they
seem.
This talk explores the domain specific language (DSL) of the deck-building card game Dominion.
We will see how actions in the game have their own language, and can be decomposed into many smaller languages. Using Tagless-Final encoding, we will define these each of these DSLs and compose them to create the larger language.
We will explore two different mechanisms of composition: extension and embedding. Finally, we will enrich the DSL with a type system that enforces game-specific constraints.
Why is functional programming hard? Are Monads really like burritos? And why do we always compare them?
Despite the wealth of resources available, many developers find functional programming challenging. In this talk, we argue that it’s not the content that we teach, but the way in which we teach it, that is important.
Stealing from the pedagogic programming language of Racket, we explore how tools such as Scalameta can help us take a different approach. At the end, we’ll be none the wiser as to what Monads truly are, but perhaps we’ll have a better path to explaining them.
Abstract data types in region of abysmal pain & how to navigate them
Abstract data types are an essential tool in a programmer's toolkit, but finding a data structure to fit them can be challenging. This is especially so for graphs, which can have complex constraints that are difficult to encode using conventional data structures. Join me in the search for a functional, typesafe graph. We will explore different graph representations, and discover how types can help us encode constraints. Using dependent types, we will construct a graph that we can prove satisfies its abstract data type.
Are you plagued with unbearably slow compile times? Do you spend your day endlessly brewing tea, waiting for scalac to respond? Have you ever tried to speed up your build, but haven’t even known where to start? You’re in luck! In this talk, we will use recent advancements in scala tooling to look under the hood of the scala compiler and see what’s slowing it down. We’ll journey through build graphs, dive into compiler phases, and even learn how to use all those seemingly obscure compiler flags. By carefully benchmarking, profiling and tweaking our builds, we will turn our compiler into a well-oiled machine.
Peeling the Banana: Recursion schemes from first principles
Recursion is at the heart of every functional programmer's toolkit, but with it comes a lot of boilerplate. In the early 1990s, the seminal paper Functional Programming with Bananas, Lenses, Envelopes and Barbed Wire (Erik Meijer, M.M. Fokkinga, and Ross Paterson) introduced a little-known technique known as recursion schemes. This technique makes recursion generic, removing much of the boilerplate associated with it, and cleanly separating business logic from recursive traversal. It paved the way to many different schemes, each for their own kind of recursive traversal.
This talk explores the technique of recursion schemes and how to use it. We start with primitive recursion, briefly diving into folds, before deriving the catamorphism, a specific recursion schema for the right fold. We shall see that there is a rich zoo of recursion schemes for different types of folds, unfolds and more.
Libra: Reaching for the stars with dependent types
When we code, we code in numerics - doubles, floats and ints. Those numerics always represent real world quantities. Each problem domain has it’s own kinds of quantities, with its own dimensions. Adding quantities of different dimensions is nonsensical, and can have disastrous consequences. In this talk, we’ll tackle the field of dimensional analysis. We’ll explore dependent types, singleton types, and dive into generic programming along the way. We’ll find that dimensional analysis can be brought much closer to home - in the compilation stage itself! And finally, we’ll end up deriving Libra - a library which brings dimensional analysis to the compile stage for any problem domain.