Jay's Projects

These are some projects I'm currently “working” on. More realistically, these are some vague ideas that I have, that I’ve made some amount of progress on. Let me know if you’re interested in any of them!

Right now, this is actually just one big project. I’ll add more stuff here and organize it better when I have time.

Haskell library for Arrowized Functional Reactive Programming in FIRST Robotics

Since I was in high school, I’ve been involved in FIRST robotics competition. I’ve generally used Java and WPILib, but been frustrated by the poor composability and confusing semantics of Commands and Subsystems. Internally, I’ve always thought about robot programs as several small, stateful pieces with inputs and outputs wired together, even if that was far from how I implemented them. A few years ago, I discovered an approach called Arrowized Functional Reactive Programming, which is everything I’ve wished for and more. I’ve started work on a Haskell library to be able to use AFRP in FIRST robotics.

Idea

Arrowized Functional Reactive Programming is a style of programming for building interactive systems in a purely functional language. The particular formulation I’m thinking of is described in the paper Functional Reactive Programming, Refactored, by Perez, Bärenz, and Nilsson.

One of the motivating examples of AFRP is robotics. You can think of the whole robot program as consuming a stream of inputs from sensors and controllers, and producing a stream of outputs to actuators, with the interesting, purely functional logic in the middle. We call this core bit of logic a signal function.

The core idea of AFRP is that you can build simple, re-usable signal functions like “PID controller” or “low-pass filter”, and then build up more complex programs by composing them with various combinators.

Haskell is especially well-suited to this for a few reasons. First, it is purely functional, so this separation between IO and pure logic can be enforced by the type system. This makes it possible to apply equational reasoning, which in my opinion is a huge conceptual win. Second, most of the combinators actually just come from Arrow and Monad classes. Haskell already has a huge ecosystem around these classes, including do and proc do notation. The upshot of this is that all the normal “control flow” operations work on signal functions, and we can just “wire inputs to outputs”.

This is just a summary. For the full story, you should really check out the links above.

What needs to be done

Core implementation of AFRP in Haskell

This is done, but not by me, in the wonderful dunai package on Hackage.

A library of signal functions useful for FRC

I’ve started work on this. The thing I’m most proud of so far is a composable “teleop controller”, which allows you to swap out parts of a signal function in response to triggers, like button presses. The controllers can be nested to an arbitrary depth, so you can have “sub-sub-systems”. The semantics can be defined by a few equations, most of which are just the Arrow and Semigroup laws (here the semigroup operation is just providing alternative behaviors for different “modes”). In WPILib, this would have been handled by canceling one command when another command has conflicting requirements. My approach has the advantage that the type system guarantees that each subsystem has exactly one thing sending it outputs at any given time, and is in my opinion easier to reason about.

There are several other ideas I’d like to try out that can come later, such as ways to automatically manage preferences or automatically send a signal function’s inputs and outputs to the dashboard for debugging. Generic could be useful for serializing and deserializing NetworkTables data. (Note: we cannot use Template Haskell when cross compiling, so we need other methods of managing boilerplate!)

Abstractions for describing hardware

While the pure logic is handled by signal functions, at some point we’ll need to specify how to do IO. While we could just manually chain together IO actions for opening, reading, writing, and closing hardware, I’d like to do something more declarative. I’ve found that hardware can be modeled as a Profunctor. This means you can compose pure functions on both the input and the output. It’s also an Applicative, which means you can combine hardware of different types. This approach makes it easy to tag hardware with metadata, such as port mappings, for static analysis. For notation, I’ve found that the language extensions ApplicativeDo and RecordWildCards make for very concise and readable code.

Bindings to the Hardware Abstraction Layer (and vendor libs)

This is partially done. I have enough of the bindings done that I can run a Haskell program against HALSim, and use PWM and other simple hardware. I don’t see any major technical obstacles here.

I plan to implement bindings as two packages: an API package and an implementation package. Your main robot program would be a library that depends on the API, and then you’d also have a “runner” program that depends on the implementation. This would allow you to run tests (including port map validation) without having to worry about linking to native libraries.

Building a cross-compiler targeting the RoboRIO

In theory, I’ve done this. After a lot of fiddling, I was able to build a cross-compiler that used the FRC toolchain, and linked against the appropriate versions of libraries. From poking around with readelf it seems to be doing the right thing. I’ve yet to test it on real hardware.

Real-world examples

I started this, using the 2018 game as an example, since my team’s robot from that year had the simplest hardware. This would be a good opportunity to demonstrate all the possibilities for offline testing this opens up.

Documenting and teaching

This is the most important part, and also the hardest part. Clearly, it will need to be more accessible than this jumble of thoughts. I’ve written up some notes, but nothing substantial yet.