4

私はこの関数を取得し、反復と takeWhile を使用して小さな実装を作成しようとしています。これらの関数を使用する必要はありません。実際には、1 行に変換しようとしているだけです。パターンは見えますが、基本的に同じコードを作成せずに、再帰の代わりに繰り返しを使用するだけで、それを悪用することはできないようです。

fun2 :: Integer -> Integer
fun2 1 = 0
fun2 n 
    | even n = n + fun2 (n `div` 2)
    | otherwise = fun2 (3 * n + 1)

どんな助けでも素晴らしいでしょう。私は何時間もこれに苦労してきました。ありがとう

4

3 に答える 3

6

でこれを行う場合iterate、重要なのはそれをより小さな論理部分に切り刻むことです。

  • ルールを使用してシーケンスを生成する

    a k+1 = a k /2 a kが偶数の場合

    a k+1 = 3a k +1 a kが奇数の場合

  • a j = 1でシーケンスを停止します( collat​​z 予想が真である場合、すべて停止します)。

  • パス上の偶数要素を除外します
  • それらを合計する

したがって、これは次のようになります。

  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

これにより、何行も節約できますが、再帰がデータの生成に変換されます。

于 2013-02-11T02:04:00.900 に答える
3

まず、あなたの 4 行バージョンに問題はないというトムのコメントに同意します。それは完全に読みやすいです。ただし、Haskell 関数を 1 つのライナーに変換するのは、楽しい練習になることがあります。誰が知っている、あなたは何かを学ぶかもしれません!

現時点であなたが持っている

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 式を s のチェーンに変換できますif(実際には、一般にこれにはEq関数の引数のインスタンスが必要ですが、Integers を使用しているので問題ありません)。

fun n = if n == 1 then 0 else if even n then n + fun (n `div` 2) else fun (3 * n + 1)

これはあなたが始めたものよりもはるかに読みにくいことに同意すると思います。

于 2013-02-11T00:08:16.443 に答える
0

一発ギャグ ;)

fun2 n = if n==1 then 0 else if even n then n + fun2 (n `div` 2) else fun2 (3 * n + 1)

私の感覚では、ルックアップ テーブルが不足していると、この関数は再帰なしでは実装できません。再帰で渡される引数が予測できないように見えるためです (2 のべき乗としての n を除く)。

一方、ランピオンは私が何か新しいことを学ぶのを助けてくれました。

于 2013-02-11T00:09:53.657 に答える