Haskell - Look Ma! No Concrete Implementation!

Posted on August 8, 2020

This is my post about tagless final encoding. There are many like it, but this one is mine. My tagless final encoding post is my best friend. It is my life. I must master it as I must master my life.

I can’t think of a good intro so I modified the Rifleman’s Creed. Anyway, the tagless final encoding technique has been very helpful in structuring my programs without being burdened about dependencies so much, because of this I can change dependencies and mostly don’t have to re-structure my program. This technique also makes it almost effortless to do unit testing.

Just like my other posts let’s do a contrived example.

This is our user story.

  • A command line tool that takes a file path to a text file that contains some text.
  • The content of the input file will be processed, and the text content will be capitalized.
  • The processed text content will then be printed to an output file.

Let’s start by creating the representation of our application.

Then, let’s define the capabilities of the app based on the made up user story. First, the cli capability.

Next, the capabalities to manipulate files in the file system.

Finally, the capability to manipulate text.

With all these capabilities, I think we are ready to assemble our program. So, let’s go back to the AppM module. We have to create instances but skip the implementation for now, and use undefined

As you can see we were able to assemble our program in interpretCLI without any concrete implementations. When we provide the concrete implementations, we won’t get so bogged down by thinking about the entire the program because we’ve already done that. We only have to think about the concrete implementations of individual capabilities. For example, we only need to think about how to retreive a file, print a file, etc.

Proceeding to our concrete implementation we can pick optparse-applicative as our cli utility and relude as our prelude.

By using optparse-applicative, here’s the implementatin of parseCommand

One obvious downside to this is the n^2 instance problem which Vasiliy Kevroletin mentions in his article.

That’s it! We import our library code to the Main module and execute the program.

References

Purescript Halogen Realworld repository

Three Layer Cake by Matt Parson

Introduction to Tagless Final by Vasiliy Kevroletin

Tagles Final Encoding by Juan Pablo Royo Sales