So I'm in need of a little assistance or at least a point in the right direction! I'm new to Haskell but I'm familiar with C# and PHP.
I'm trying to create a FizzBuzz function that allows 3 parameters to be entered. I understand the general concept of FizzBuzz but I'm trying to be able to create a function that allows you to put the first divisor, second divisor and the last parameter as an upper range. The part where I'm struggling to understand is how you assign input values to variables in a function.
I found different tutorials showing how to do the regular FizzBuzz in Haskell.
So my main questions would be this:
How do you assign input values to variables? I know how to assign the type, which would be something like this but I don't know how you would reference it in a function.
fz' :: [Integer, Integer, Integer] -> Integer -> Integer -> Integer
From what I've read online, it's better to separate the functions instead of having one large function to perform everything. With that being said, would it be best to have:
a. One function receive the input values and assign them variables, then call separate functions?
b. In the separate functions, set the range and then do divideBy
or mod
to check if value x
is divisible by [1..z]
print fizz, if x
and y
are divisble by [1..z]
print fizzbuzz, if y
is divisible by [1..z]
print buzz? Is it better to use a where
clause or case
?
c. Separate function that implements the values for the range and (x,y,z)
?..
Any ideas, tips, help?
In PHP you define a function like this:
function abc($x, $y) { ... }
In Haskell you would do it this way:
abc x y = ...
and if you wanted to add a type signature:
abc :: Int -> String -> Whatever
abc x y = ...
A Haskell version of your generalized fizz-buzz might be defined like this:
myFizzBuzz :: Int -> Int -> Int -> [String]
myFizzBuzz div1 div2 upperBound =
-- here `div1` is the first divisor, `div2` the second
-- and `upperBound` is the upper bound of the range
...
-- return a list of strings, e.g. ["Fizz", "Fizz", "Buzz", ... ]
Note that myFizzBuzz
returns a list of Strings - it doesn't print them out. To print them out just join the resulting words with lines
and call putStrLn
:
printMyFizzBuzz div1 div2 upperBound =
putStrLn $ lines (myFizzBuzz div1 div2 upperBound)
This also illustrates the separation of IO from computation which is prevalent in Haskell programs: you structure your program as mainly a pure computation surrounded by a thin IO-layer. In this case myFizzBuzz
is your pure function. A complete program which takes it's parameters from the console might look like this:
main = do
(arg1 : arg2 : arg3 : _) <- fmap words getLine -- IO layer
let div1 = read arg1 -- pure core
div2 = read arg2 -- |
upperBound = read arg3 -- |
let results = myFizzBuzz div1 div2 upperBound -- pure core
putStrLn $ lines results -- IO layer
One reason to write pure functions is that they tend to be more reusable.
Instead of specifying an upper bound in myFizzBuzz
what about writing it to generate an infinite series of "Fizz" and "Buzz" strings:
allFizzBuzz :: Int -> Int -> [String]
allFizzBuzz div1 div2 = ...
-- the infinite Fizz-Buzz sequence for divisors div1, div2 starting with 1
Then the myFizzBuzz
is simply the take
function composed with allFizzBuzz
:
myFizzBuzz div1 div2 upperBound = take upperBound (allFizzBuzz div1 div2)