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
我在使用 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