This is a brief exploration of some of the capabilities of the F# language to define a small set of classes that can be leveraged to provide a simple text-based UI for an F# program. Example code is provided, which is a great introduction to the syntax, but a gentler and more thorough introduction to F# can be found at MSDN Visual F#.
After learning more about the language from a series of F# videos, I decided to explore the language and tinker with it for a while. One of the first challenges a developer will face working with a new language is settling on a simple means to display results to the screen and get input from the user. F# can import .NET assemblies, which are certainly sufficient, but working on a basic text console it turned out to be an interesting way to explore the language. Admittedly, this is not a problem domain specifically suited for F#, but it exercises some of the fundamental capabilities of the language and is grounded in the familiar territory of the command line console.
Here’s a screenshot of what the final text console test program looks like, which renders its interface using the F# BoxConsole module.
Each of the boxes shown represents an instance of one of the classes defined in the BoxConsole module using structures to define the box location, size and style. The menu box in the center is an example of a DosMenu class which combines all of the building block classes to implement an F# application menu.
One of the fundamental affordances a programming language can provide is a mechanism to map enumerated integer values to a set of constant symbols, a.k.a. an Enumeration. F# employs it’s pattern matching syntax to define an enumeration and here are some examples from the BoxConsole module:
The first enumeration, BoxCorner expresses a shorthand to refer to the upper left, upper right, lower right and lower left corners of a box and the TextAlignment enumeration allows the users of the BoxConsole module to specify a left, center or right text justification.
Another fundamental programming language expression is the data record or structure that contains a collections of related values. The BoxLocation type defines a F# data structure to collect the data describing the size and position of a box.
The BoxStyle type describes the style of a DosBox, including members that describe the border style, margin around the text along with foreground and background colors of the box. In the case of the BoxStyle type, the Border member refers to an object and not a simple data type.
The “immutable by default” nature of F# encourages developers to craft code that the complier can optimize much more aggressively and runs faster in a parallel execution context. However, at the end of the day, the program must have a reasonable way to express it’s state. The mutable keyword is the signal to F# that the variable being declared will be used in the more traditional manner: its value should be stored and can be expected to change during program execution. These mutable variables can then be used as fields to store values for the implementation of a class.
(Note: Due to encoding issues, the contents of boxPatterns are not correctly rendered above. To see the complete set of character used, please download the project source code.)
Those new to F# but familiar with today’s object-oriented patterns should be able to recognize those patterns peeking through this alien code if they “squint” just a little bit. The static keyword is used to express functionality within the class scope, and is omitted for instance members of a class. Creation of objects is achieved via the new keyword, which also used to declare class constructors. Also notice the use of the private keyword allowing the developer to control the visibility of members in order to help maintain encapsulation.
The BorderStyle class knows how to render a nine character array as a the corners and edges of a box. One constructor uses a predefined style and the other allows the caller to specify a custom set of nine characters to define a border style. This class is effectively implemented with a couple pattern matching methods.
The first, boxPart, matches determines which offset to use to (0-2) depending on if it’s the first item in the list (yields 0), the last item in the list (2), or any other item in the list (1). Similar matching rules are employed in the BoxLines function, but that pattern is wrapped in an array [| for w in 1 .. width –> |] generated from a list [ for h in [1..height] –> ]. Together, these two functions provide the character patterns for the box’s border style given a width and height.
Class ConsoleUI wraps the System.Console class for the BoxConsole module, making the console easier to use from the F# implementation. F# uses the open keyword to import other type libraries into the current program scope. In this case we import the System .NET module on line six, right after we explicitly declare the name of our module on line four.
Taking a closer look at one of the ConsoleUI methods reveals how .NET methods and properties can be called from an F# application. The WriteAt function will write a message on the console in the requested location and will trim the message to prevent the console screen from scrolling.
Note the use of the variables oleft and otop which are used to store the current cursor position so it can be restored once the message is written. These variables are written to once and never modified. They are given their values using the let keyword and the equals (=) sign and they are immutable, the value is bound that that name. Even in the case of message, the value is is not mutable: the old value of message is lost and a new one (possibly shorter) is created.
On the other hand, the .NET system Console.CursorLeft property is not immutable and must be modified to change the cursor position. In this case F# considers the variable mutable and allows its value to be changed using the <- operator. Finally, the WriteAt function provides an example of calling a method on a .NET class, writing the message to the console using the Console.Write(message: string) syntax to invoke the method.
Program.fs is provided as a practical example of how to use the BoxConsole module to display and process user selections using the DosMenu class, and allows the user to cycle through some of the various styles and options available.
The example first declares the module name and imports the System and BoxConsole types. The program then creates the DosMenu containing a list of the box styles through which the user can cycle. Next the program declares a set of working variables. It’s interesting to note that like many other program there is a mix of immutable and mutable variables, but in F# it’s mutable variables that are the exception that require additional semantic notation.
Next the program creates a DosBox that displays the time and then enters the main program while loop where it will run until the user selects “Quit”. In the body of the main loop, if the user has made a selection then the program options are updated. Finally, the program will pause for 1000ms to wait for the user’s next selection from the DosMenu.
Download complete BoxConsole source code.