4

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?

2
  • 1
    I think this is an example of (or similar to) defunctionalization. Commented Feb 4, 2024 at 20:24
  • 1
    Reminds me of free monads Commented Feb 4, 2024 at 20:59

1 Answer 1

3

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.

Sign up to request clarification or add additional context in comments.

2 Comments

I'm familiar with Functional Core Imperative Shell since before, but I was kind of hoping that this had an even more established name. It seems to me like "free monads" and the "Definitional interpreters for higher-order programming languages" paper by John C. Reynolds might serve as some adequate theoretical reading for me.
@RasmusKällqvist That paper I don't know, but I suppose if you want something more theoretical you could also frame the problem in terms of F-Algebras.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.