Last active
August 29, 2015 14:15
-
-
Save beala/59908630f12e844db655 to your computer and use it in GitHub Desktop.
Free monad for declarative fizz buzz
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# LANGUAGE DeriveFunctor #-} | |
import Control.Monad.Free | |
import Data.List | |
data FizzBuzz f a = FizzBuzz (Factor f) String a deriving Functor | |
newtype Factor a = Factor a | |
-- A fizz buzz action that produces a String if the Integral is a factor. | |
fizzbuzz :: (Show a, Integral a) => a -> String -> Free (FizzBuzz a) () | |
fizzbuzz fa message = liftF (FizzBuzz (Factor fa) message ()) | |
-- Run a FizzBuzz program over a single Integral. | |
runFizzBuzz :: (Show a, Integral a) => a -> Free (FizzBuzz a) b -> String | |
runFizzBuzz i prog = runFizzBuzz_ i [] prog | |
runFizzBuzz_ :: (Show a, Integral a) => a -> [(Factor a, String)] -> Free (FizzBuzz a) b -> String | |
runFizzBuzz_ num factors (Free (FizzBuzz fa msg n)) = | |
runFizzBuzz_ num ((fa, msg):factors) n | |
runFizzBuzz_ num factors (Pure _) = | |
let inOrderFactors = reverse factors | |
divisibleFactors = filter (\ (Factor fa, _) -> num `divisibleBy` fa) inOrderFactors | |
messages = fmap (\(_, msg) -> msg) divisibleFactors in | |
if (length messages > 0) then concat messages else show num | |
where | |
n `divisibleBy` m = (n `mod` m) == 0 | |
-- Run a FizzBuzz program over a range of Integrals. | |
runFizzBuzzRange :: (Show a, Integral a) => a -> a -> Free (FizzBuzz a) b -> String | |
runFizzBuzzRange start end prog = | |
let messages = fmap (\i -> runFizzBuzz i prog) [start..end] in | |
intercalate "\n" messages | |
program :: Free (FizzBuzz Int) () | |
program = do | |
fizzbuzz 5 "Fizz" | |
fizzbuzz 3 "Buzz" | |
fizzbuzz 2 "Zork" | |
fizzbuzz 7 "Bonk" | |
fizzbuzz 10 "Bang" | |
main :: IO () | |
main = do | |
putStrLn $ runFizzBuzzRange 1 100 program |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
1
Zork
Buzz
Zork
Fizz
BuzzZork
Bonk
Zork
Buzz
FizzZorkBang
11
BuzzZork
13
ZorkBonk
FizzBuzz
Zork
17
BuzzZork
19
FizzZorkBang
BuzzBonk
Zork
23
BuzzZork
Fizz
Zork
Buzz
ZorkBonk
29
FizzBuzzZorkBang
31
Zork
Buzz
Zork
FizzBonk
BuzzZork
37
Zork
Buzz
FizzZorkBang
41
BuzzZorkBonk
43
Zork
FizzBuzz
Zork
47
BuzzZork
Bonk
FizzZorkBang
Buzz
Zork
53
BuzzZork
Fizz
ZorkBonk
Buzz
Zork
59
FizzBuzzZorkBang
61
Zork
BuzzBonk
Zork
Fizz
BuzzZork
67
Zork
Buzz
FizzZorkBonkBang
71
BuzzZork
73
Zork
FizzBuzz
Zork
Bonk
BuzzZork
79
FizzZorkBang
Buzz
Zork
83
BuzzZorkBonk
Fizz
Zork
Buzz
Zork
89
FizzBuzzZorkBang
Bonk
Zork
Buzz
Zork
Fizz
BuzzZork
97
ZorkBonk
Buzz
FizzZorkBang