我对Haskell很陌生,正在尝试编写一个简单的函数,该函数将整数数组作为输入,然后返回所有元素的乘积或平均值,具体取决于数组分别是奇数还是偶数长度。
我了解如何为递归设置基本案例,以及如何为不同的情况设置布尔守卫,但我不明白如何协同执行这些操作。
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
目前我收到错误
"parse error on input '=' Perhaps you need a 'let' in a 'do' block?"
但我不明白我如何在这里使用let
。
您之所以有守卫,是因为您尝试在实际查看列表中的值之前确定列表的长度。
与其进行多次传递(一次用于计算长度,另一次用于计算总和或乘积(,不如在浏览列表时计算您可能需要的所有值,然后在最后做出决定并返回适当的值:
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
您可以采取多种措施来减少内存使用量,递归只是重新实现一个折叠,但这可以让您了解如何一次性计算答案。
定义一个辅助内部函数,如下所示:
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
这仅涉及您问题中的语法问题。特别是,[Integer]
不是一个数组 - 它是一个整数列表。
但当然,变量的名称不会影响代码的正确性。
如果不关注递归,这应该是一个可接受的解决方案:
arrayFunc :: (Integral a) => [a] -> a
arrayFunc ls
| n == 0 = 1
| even n = (sum ls) `div` (fromIntegral n)
| otherwise = product ls
where
n = length xs