Haskell迷你函数的实现

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) 任何帮助都会很好。我已经为此挣扎了好几个

我一直在尝试使用这个函数,并使用iterate和takeWhile进行小型实现。它不必使用这些函数,实际上我只是想把它变成一行。我可以看到其中的模式,但如果没有基本相同的代码,我似乎无法利用它,只是使用迭代而不是递归

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