我一直在尝试使用这个函数并使用iterate和takeWhile进行小型实现。它不必使用这些功能,我只是想把它变成一行。我可以在其中看到模式,但是我似乎无法在没有基本相同的代码的情况下利用它,只需使用迭代而不是递归。
fun2 :: Integer -> Integer
fun2 1 = 0
fun2 n
| even n = n + fun2 (n `div` 2)
| otherwise = fun2 (3 * n + 1)
任何帮助都会很棒。几个小时以来我一直在努力。 感谢
答案 0 :(得分:6)
如果你想用iterate
做到这一点,关键是把它砍成更小的逻辑部分:
使用规则生成序列
a k + 1 = a k / 2如果 k 甚至
a k + 1 = 3a k +1如果 k 奇数
在 j = 1处停止序列(如果collatz conjecture为真,则全部完成)。
那么这就变成了:
f = sum . filter even . takeWhile (>1) . iterate (\n -> if even n then n `div` 2 else 3*n + 1)
但是,我确实认为使用帮助函数会更清楚
f = sum . filter even . takeWhile (>1) . iterate collatz
where collatz n | even n = n `div` 2
| otherwise = 3*n + 1
这可能不会为您节省任何行,但会将您的递归转换为数据生成。
答案 1 :(得分:3)
首先,我同意汤姆的评论,即你的四行版本没有任何问题。它完全可读。但是,将Haskell函数转换为一个衬里偶尔会很有趣。谁知道,你可能会学到一些东西!
目前你有
fun 1 = 0
fun n | even n = n + fun (n `div` 2)
| otherwise = fun (3 * n + 1)
您始终可以使用警卫将表达式转换为if
fun 1 = 0
fun n = if even n then n + fun (n `div` 2) else fun (3 * n + 1)
您始终可以将一系列模式匹配转换为案例表达式:
fun n = case n of
1 -> 0
_ -> if even n then n + fun (n `div` 2) else fun (3 * n + 1)
最后,你可以将case表达式转换为if
s的链(实际上,通常这需要一个Eq
实例作为函数的参数,但是因为你正在使用Integer
这没关系。)
fun n = if n == 1 then 0 else if even n then n + fun (n `div` 2) else fun (3 * n + 1)
我认为你会同意这比你开始时的可读性差得多。
答案 2 :(得分:0)
一个班轮;)
fun2 n = if n==1 then 0 else if even n then n + fun2 (n `div` 2) else fun2 (3 * n + 1)
我的感觉是缺少查找表,没有递归就无法实现此函数,因为在递归中传递的参数似乎是不可预测的(除了n为2的幂)。
另一方面,猖獗让我学到了新的东西。