Created
December 19, 2018 00:53
-
-
Save AnthonySuper/112c786dfe72365d01369a662ee46866 to your computer and use it in GitHub Desktop.
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
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