Multiple input values with upper range

2019-09-08 18:44发布

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:

  1. 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
    
  2. 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?

1条回答
forever°为你锁心
2楼-- · 2019-09-08 19:14

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)
查看更多
登录 后发表回答