Rasmus Källqvist
Rasmus Källqvist

Reputation: 332

Name for representing commands as data in functional languages?

This is a question about the name of what appears to me to be a very common pattern in functional programming.

In pure functional programming languages like Haskell, you often have an "outer" part of the program allowed perform IO side effects like printing to the screen or writing to a data base (e.g. the IO monad), and then an inner part of the program consisting of just pure functions.

If the pure functions want to perform some kind of side effect, like printing, it can be represented as a value of an algebraic data type that is returned to the outer IO part, where it will then be executed.

Here's a somewhat contrived example:

data Command = PutStrLn String

fizz :: Int -> Command
fizz n | n `mod` 15 == 0  = PutStrLn "FizzBuzz"
       | n `mod` 3  == 0  = PutStrLn "Fizz"
       | n `mod` 5  == 0  = PutStrLn "Buzz"
       | otherwise        = PutStrLn (show n)
       
runCommand :: Command -> IO ()
runCommand (PutStrLn str) = putStrLn str
       
main :: IO ()
main = mapM_ runCommand $ map fizz [1..100]

The fizz function is completely pure, but instead of just returning a String I've opted for the string as well as the intended effect. Using fizz buzz here is just a toy example to show the relation between the Command type and the effectful runCommand function.

In a more complicated program, fizz would be some part of my application logic, and the Command could be e.g. representing a web API or OS calls or some other IO effect.

Is there a name for representing effectful APIs with data in this manner?

Upvotes: 4

Views: 107

Answers (1)

Mark Seemann
Mark Seemann

Reputation: 233125

I've often seen the pure part described as an Abstract Syntax Tree (AST) of a Domain-Specific Language (DSL), and the 'run' function as an interpreter of that language.

As Fyodor Soikin mentions in the comments, free monads can be viewed as an example of that style of programming.

Gary Bernhardt calls it Functional Core, Imperative Shell.

Often the AST is defined as a recursive sum type, and since sum types are isomorphic to the Visitor pattern, you may also view the interpreter as a Visitor if you're in a more object-oriented mood. (To be clear, not in Haskell, but in other contexts.)

It seems to me that this style of programming pops up in several places independently, and often one author/inventor is unaware of prior art. Thus, you'll find different names even though there's lots of overlap.

Upvotes: 3

Related Questions