What is the syntax for different recursions depending on two boolean guards?

125 Views Asked by At

I'm very new to Haskell and am trying to write a simple function that will take an array of integers as input, then return either the product of all the elements or the average, depending on whether the array is of odd or even length, respectively.

I understand how to set a base case for recursion, and how to set up boolean guards for different cases, but I don't understand how to do these in concert.

arrayFunc :: [Integer] -> Integer                                                                                       
arrayFunc [] = 1                                                                                                        
arrayFunc array                                                                                                           
| (length array) % 2 == 1 = arrayFunc (x:xs) = x * arrayFunc xs                                                     
| (length array) % 2 == 0 = ((arrayFunc (x:xs) = x + arrayFunc xs) - 1) `div` length xs 

Currently I'm getting an error

"parse error on input '='
Perhaps you need a 'let' in a 'do' block?"

But I don't understand how I would use a let here.

3

There are 3 best solutions below

7
On BEST ANSWER

Define an auxiliary inner function like that:

arrayFunc :: [Integer] -> Integer
arrayFunc [] = 1
arrayFunc array
  | (length array) % 2 == 1  =  go1 array
  | (length array) % 2 == 0  =  go2 array
  where
    go1 (x:xs)  =  x * go1 xs
    go2 (x:xs)  =  ((x + go2 xs) - 1) `div` length xs 

This deals only with the syntactical issues in your question. In particular, [Integer] is not an array -- it is a list of integers.

But of course the name of a variable doesn't influence a code's correctness.

1
On

The reason you have guards is because you are trying to determine the length of the list before you actually look at the values in the list.

Rather than make multiple passes (one to compute the length, another to compute the sum or product), just compute all of the values you might need, as you walk the list, and then at the end make the decision and return the appropriate value:

arrayFunc = go (0, 1, 0, True)
  where go (s, p, len, parity) [] = 
               if parity  then  (if len /= 0 then s `div` len else 0) 
                          else  p
        go (s, p, len, parity) (x:xs) = 
               go (s + x, p * x, len + 1, not parity) xs

There are various things you can do to reduce memory usage, and the recursion is just reimplementing a fold, but this gives you an idea of how to compute the answer in one pass.

0
On

Without focus on recursion this should be an acceptable solution:

arrayFunc :: (Integral a) => [a] -> a
arrayFunc ls
    | n == 0     = 1
    | even n     = (sum ls) `div` (fromIntegral n)
    | otherwise  = product ls
    where
    n     = length xs