about

Introduction

When writing code for a robot, there are a number of languages available for use.
While investigating C# for use, I decided to make a detour and attempt to create robot code using F#.
I found that it allowed for a surprising functional programming twist.

The Code

F# code has a strict ordering - symbols are only visible if they occur before their use, both within a file and within the project's file list.
Because of this, I'm writing about the order that I found works best for my tests.

RobotMap

The RobotMap is normally the simplest part of robot code - it stores the constants that map sensors and manipulators, so that two different subsystems don't try to use the same ones and cause conflict.
Declaring constants in F# is easy:

Subsystems

Finally, on to the interesting stuff.
I'll only show one, but it'll demonstrate the core concepts.

// A new class is made with the type keywordtypeAManipulators()=// The type AManipulators inherits from SubsysteminheritSubsystem()// The AManipulators has a double-solenoid with ports from RobotMapletsolenoid=newDoubleSolenoid(RobotMap.Solenoid.AManipulatorForward,RobotMap.Solenoid.AManipulatorReverse)// A property representing the state of the manipulators// F# doesn't declare a "this" keyword, it's manually specifiedmemberthis.State// When you read the state, it runs thiswithget()=ifsolenoid.Get()=DoubleSolenoid.Value.ReversethenLoweredelseRaised// When you set the state, it runs thisandsetvalue=solenoid.Set(matchvaluewith|Lowered->DoubleSolenoid.Value.Reverse|Raised->DoubleSolenoid.Value.Forward)// A private method creating a new command// Note that this is internal to the class, instead of declaring the commands as classes separately// This allows the rest of the robot to access the commands as members of an instance of the subsystemmemberprivatethis.SetStatestate={newInstantSubsystemCommand(this)withoverridecmd.Initialize()=this.State<-state}// Here are public accessors for SetState// These will be used when calling and constructing commandsmemberthis.Lower()=this.SetStateLoweredmemberthis.Raise()=this.SetStateRaised// This subsystem doesn't do anything until commandedoverridethis.InitDefaultCommand()=()// Properly manage cleanup code in .NET landinterfaceIDisposablewithoverridethis.Dispose()=solenoid.Dispose()

The most important part here is that the subsystem owns all of the commands that can operate on it.
This means that all subsystem logic is tracked together.

Program

The main body of the program, Program.fs, contains not just the main robot class, but also the definitions for all complex commands

This code snippet shows off the fun part - declaring command groups.
In C#, as well as the Java and C++ versions of WPILib, command groups are declared by inheriting from CommandGroup, and then in the constructor adding calls to addSequential and addParallel.
With the definitions of the +- and +| operators, from the Extensions.fs, each call to addSequential can be chained together in a less verbose way.
Each of these are also converted to functions, instead of subclassing, because it's the more idiomatic way to do so within F#.

Again, each command is accessed via the subsystem that it belongs to.
Because of this, the code reads more intuitively, with an ironically more object-oriented seeming interface than is possible in any other language.