Skip to content

Instantly share code, notes, and snippets.

@andyfriesen
Last active August 10, 2021 18:25
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andyfriesen/43d886ce60927c69b3d1 to your computer and use it in GitHub Desktop.
Save andyfriesen/43d886ce60927c69b3d1 to your computer and use it in GitHub Desktop.
Tiny example showing how to force your Haskell code to be 100% deterministic under unit tests
{-# LANGUAGE FlexibleInstances #-}
module Main where
import Control.Applicative ((<$>))
import Control.Monad.State.Lazy as S
class Monad m => World m where
writeLine :: String -> m ()
instance World IO where
writeLine = putStrLn
data FakeState = FS { fsWrittenLines :: [String] }
deriving (Show)
def :: FakeState
def = FS { fsWrittenLines = [] }
instance World (S.State FakeState) where
writeLine s = do
oldLines <- fsWrittenLines <$> S.get
S.put FS { fsWrittenLines = s:oldLines }
runFakeWorld :: b -> State b a -> (a, b)
runFakeWorld = flip S.runState
importantBusinessAction :: World m => m String
importantBusinessAction = do
writeLine "This action is prohibited from doing any untestable IO."
writeLine "Writing to stdout is testable, though, so this is all ok."
return "Pickles"
main :: IO ()
main = do
_ <- importantBusinessAction
let (result, endState) = runFakeWorld def importantBusinessAction
print endState
print result
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment