Skip to content

Instantly share code, notes, and snippets.

@AnthonySuper
Created December 19, 2018 00:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AnthonySuper/112c786dfe72365d01369a662ee46866 to your computer and use it in GitHub Desktop.
Save AnthonySuper/112c786dfe72365d01369a662ee46866 to your computer and use it in GitHub Desktop.
module FizzBuzz where
-- The type of functions which can do a fizzbuzz-like thing.
-- That is, they will output something besides their input based on
-- some conditions.
newtype FizzBuzzer b a = FizzBuzzer (b -> Maybe a)
-- If the FizzBuzzer outputs a semigroup, or something that can be combined,
-- then we can very easily combine FizzBuzzers. More specifically,
-- this is what lets us implement the "if it is divisble by both, print
-- FizzBuzz" portion of the problem.
instance (Semigroup a) => Semigroup (FizzBuzzer b a) where
(FizzBuzzer f) <> (FizzBuzzer y) = FizzBuzzer $ f <> y
-- Similarly, if we have a monoid, we can make a "default" FizzBuzzer.
-- This is the FizzBuzzer that never returns anything.
instance (Monoid a) => Monoid (FizzBuzzer b a) where
mempty = FizzBuzzer mempty
-- This allows us to "run" a fizzBuzzer.
-- Traditionally, if we cannot print "Fizz" or "Buzz", we print the number.
-- In our more abstract case, if we can't print anything in place of our
-- input, we just print our input. So this requires that our input is
-- in some way printable, thus the Show constraint.
runFizzBuzzer :: (Show a)
=> FizzBuzzer a String -> a -> String
runFizzBuzzer (FizzBuzzer fb) a = maybe (show a) id $ fb a
-- Create a "basic" fizzBuzzer.
-- More specifically, take a number and a value, and use that value
-- if and only if the input is divisible by that number.
basicFizzBuzzer :: (Integral a, Semigroup b)
=> a -> b -> FizzBuzzer a b
basicFizzBuzzer m f = FizzBuzzer (basicFizzBuzzer' m f)
where
basicFizzBuzzer' m f a
| a `mod` m == 0 = Just f
| otherwise = Nothing
-- "If the number is divisible by 3, print Fizz"
basicFizz = basicFizzBuzzer 3 "Fizz"
-- "If the number is divisible by 5, print Buzz"
basicBuzz = basicFizzBuzzer 5 "Buzz"
-- Run a fizzBuzz style program over all the numbers
runFizzBuzz f = map (runFizzBuzzer f) [1..]
-- And the actual FizzBuzz program.
fizzBuzz = funFizzBuzz (basicFizz <> basicBuzz)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment