DSLs with the Free Monad in Java 8 : Part II

John McClean
5 min readJul 11, 2017

--

This article builds on DSLs with the Free Monad in Java 8 : Part I and Simulating Higher Kinded Types in Java . In DSLs with the Free Monad we covered the creation of a simple DSL and program using a simpler / Java friendly version of the Free Monad from cyclops-react called Unrestricted.

In this article we will re-implement the same DSL, in a full blown, Higher Kinded version of Free (also from cyclops-react), and still in Java 8. The focus of this article is introducing the building blocks neccessary to implement (or simulate) Higher Kinded Types in Java, we will rework the same examples from part I so that they are encoded at a level of abstraction normally only in seen in languages with more advanced type systems such Scala or Haskell but in plain ol’ Java 8!

Photos by Teddy Kelley, Matthew Kane, Matt Palmer via Unsplash

Higher Kinded Functors and Commands

In Part I we made use of a Transformable class that represents a type with a map operation (a functor!) and in Simulating Higher Kinded Types in Java we created a Higher Kinded equivalent of this interface.

By providing a Higher Kinded encoding for our Commands, we can migrate our DSL to use our new Functor interface rather than Transformable. The easiest way to do this (as a first step refactoring), is simply to have Command implement Higher. Our Functor instance can delegate the map operation to the map method on each Command.

Defining a Functor instance for our Command type is straight forward as we can simply delegate to our pre-existing map method.

Expressing a Higher Kinded Free in Java

From part I our simple program was

In this program we want to

output A to the console

ring a bell

output B to the console

terminate

With our new Functor we can define this program using the Higher Kinded Free type in cyclops-react. One last refactoring before we do so is to modify our ‘lifting’ methods to use Free. The required change is pretty small, switch from Unrestricted to Free (passing in the witness type Command.µ) and when we call liftF on Free we also pass in our Command Functor.

Once we have done this, we are ready to express our program in Free.

Cleaning up the Interpreter

The last piece of the puzzle is to refactor the interpet method to use Free. While we are it we can also take a little time to clean up the code.

Our Interpreters from Part I used the visit method on the type returned from the resume method to ‘pattern match’ and extract the next command from Free. Inside the matchCommand method itself we used a gnarly traditional if/then/else block to determine how to handle the command. There are three different commands so we do an if / then / else check for each one in turn. Not only is this code difficult to read, it also opens up the possibility of bugs and mistakes. The compiler will not help us if we miss an else if statement!

Either types and Pattern matching

cyclops-react provides the visit method as a way to deconstruct (or fold over) the internal state of it’s data types. This is pretty much the same approach as is taken in pattern matching in functional languages (and dual paradigm languages like Scala today and Java in the future). While we wait on the Java compiler team to implement this support for us, we can move forward today by selecting appropriate representative data types for our data.

When data is potentially nullable we can make use of an Optional (or Maybe) type, we can ‘visit’ Optional and execute one function when data is present, or a supplier when it is empty.

If we have a choice of two data types (let’s call them type A and type B) we can make use of an Either (or Xor) type. That is, we can have one thing or the other (Either A or B : Either<A,B>). When we fold / or visit this type, we will provide two functions. One will be executed when type A is present and the other when type B is present.

If we have choice of three types (for example an Output, Bell or Done command) we can define this via an Either3 (Either3<Output,Bell,Done>). Making use of an Either3 inside our Interpreter will significantly improve our code. It will look cleaner and be more robust to future changes. It will be more difficult for an engineer to refactor a change to our logic that drops one of the key conditions.

Let’s add support for our own visitor to the Command interface

Implementing visit is really simple. In each sub-type we return an appropriate instance of Either3. The compiler will help us, we won’t be able to put the wrong type in the wrong the place!

In our interpreter we can replace our unruly if / then / else chain with a type safe and exhaustive alternative call to visit on Command.

Part III: Taking this further

Only a few small changes were required to migrate our original example to use the Higher Kinded version of Free. As usual the entire code is available for you to checkout and play with on github here (https://github.com/johnmcclean-aol/unrestricted-example1).

Do join us for the next installment where we will show how pass data between commands in your programs, and also how to interleave the execution of two programs via the zip operator.

References

[http://www.haskellforall.com/2012/06/you-could-have-invented-free-monads.html](http://www.haskellforall.com/2012/06/you-could-have-invented-free-monads.html)

--

--

John McClean

Architecture @ Verizon Media. Maintainer of Cyclops. Twitter @johnmcclean_ie