Kaprekar 的例程 - Haskell 实施

Kaprekar's Routine - Haskell Implementation

我在使用 Haskell 时遇到了一些麻烦。我正在执行 Kaprekar 的例程 (http://en.wikipedia.org/wiki/6174_%28number%29),除了能够成功打印例程生成的数字列表之外,我已经完成了所有工作。所以,如果我输入数字 5432,我希望输出为 [5432, 3087, 8352, 6174]。

这是我的代码:

kaprekarList :: Integer -> [Integer]

kaprekarList x = n
  where p = kaprekar x
        n =
          if p == 6174
              then [p]
              else
                -- add to list of kaprekar numbers
                kaprekarList p

非常感谢任何帮助!

虽然不是最漂亮的例程(并且有一个小问题见下文),但您的例程似乎有效(如果 kaprekar 函数有效),所以我想您的问题确实存在。

这里有一个简单的实现和你的函数:

kaprekar :: Integer -> Integer
kaprekar n = big - small
  where big = read digits
        small = read (reverse digits)
        digits = take 4 $ (reverse . sort . show $ n) ++ "0000"

kaprekarList :: Integer -> [Integer]
kaprekarList x = n
  where p = kaprekar x
        n =
          if p == 6174
              then [x, p]
              else
                -- add to list of kaprekar numbers
                x : kaprekarList p

请注意细微的变化,以便您可以看到完整的推导,而不仅仅是最后一个元素(始终是固定的)。

替代版本

kaprekarList :: Integer -> [Integer]
kaprekarList x = x : if x == 6174 then [] else kaprekarList (kaprekar x)

这个看起来比较地道,但不会包括最后的 6174

kaprekarList :: Integer -> [Integer]
kaprekarList x = takeWhile (/= 6174) $ iterate kaprekar x

这个会(但很丑 - 也许有人知道前奏中的 takeUntil 之类的东西?):

kaprekarList :: Integer -> [Integer]
kaprekarList x = (takeWhile (/= 6174) $ iterate kaprekar x) ++ [6174]

这里是一个实现:

import Data.List (sort)

-- Convert a number to a list of digits
digits :: Integral x => x -> [x]
digits 0 = []
digits x = digits (x `div` 10) ++ [x `mod` 10]

-- Convert a list of digits to a number
undigits :: Integral x => [x] -> x
undigits = foldl (\ a b -> a * 10 + b) 0

-- Compute the next Kaprekar number
nextKapNumber :: Integral x => x -> x
nextKapNumber x = b - a
  where n = sort . digits $ x
        a = undigits n
        b = undigits . reverse $ n

-- Compute the Kaprekar list for a number
kapList :: Integral x => x -> [x]
kapList x = genList [x]
  where genList as@(6174:_) = reverse as
        genList as@(a:_)    = genList $ nextKapNumber a : as

main :: IO ()
main = putStrLn . show $ kapList 5432