Haskell迷你函数的实现
我一直在尝试使用这个函数,并使用iterate和takeWhile进行小型实现。它不必使用这些函数,实际上我只是想把它变成一行。我可以看到其中的模式,但如果没有基本相同的代码,我似乎无法利用它,只是使用迭代而不是递归Haskell迷你函数的实现,haskell,Haskell,我一直在尝试使用这个函数,并使用iterate和takeWhile进行小型实现。它不必使用这些函数,实际上我只是想把它变成一行。我可以看到其中的模式,但如果没有基本相同的代码,我似乎无法利用它,只是使用迭代而不是递归 fun2 :: Integer -> Integer fun2 1 = 0 fun2 n | even n = n + fun2 (n `div` 2) | otherwise = fun2 (3 * n + 1) 任何帮助都会很好。我已经为此挣扎了好几个
fun2 :: Integer -> Integer
fun2 1 = 0
fun2 n
| even n = n + fun2 (n `div` 2)
| otherwise = fun2 (3 * n + 1)
任何帮助都会很好。我已经为此挣扎了好几个小时了。
谢谢首先,我同意汤姆的意见,你的四行版本没有问题。它完全可读。然而,将Haskell函数转换为一行程序有时是一个有趣的练习。谁知道呢,你可能会学到一些东西 现在你有
fun 1 = 0
fun n | even n = n + fun (n `div` 2)
| otherwise = fun (3 * n + 1)
如果
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表达式转换为一个ifs的链(实际上,一般来说,函数的参数需要一个Eq
实例,但是因为您使用的是Integer
s,所以这并不重要)
我想你会同意,这远不如你开始时的可读性。One liner;)
我的感觉是,缺少查找表,这个函数在没有递归的情况下无法实现,因为在递归中传递的参数似乎不可预测(除了n为2的幂)
另一方面,rampion帮助我学到了一些新的东西。如果你想用迭代来实现这一点,关键是把它分解成更小的逻辑部分:
- 使用规则生成序列
ak+1=ak/2,如果ak为偶数
如果ak为奇数,则ak+1=3ak+1
- 在aj=1时停止序列(如果该值为真,则全部停止)
- 过滤掉路径上的偶数元素
- 求和
那么这就变成了:
f = sum . filter even . takeWhile (>1) . iterate (\n -> if even n then n `div` 2 else 3*n + 1)
不过,我确实认为使用helper函数会更清楚
f = sum . filter even . takeWhile (>1) . iterate collatz
where collatz n | even n = n `div` 2
| otherwise = 3*n + 1
这可能不会保存任何行,但会将递归转换为数据的生成。4行版本有什么问题?我认为它非常清晰,读起来比任何一行的版本都要好。这只是Haskell类的一个挑战。我花了这么多时间在这上面,我真的只是想得到一些建议。我有一个稍微精简的版本。是的,您的if语句行正是我所想的,但无法理解如何实现。助手功能也很棒。谢谢你,伙计。
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