在Haskell中一起添加两个函数

时间:2018-04-12 07:48:21

标签: haskell

嗨,我是Haskell的新手,我遇到了一个有趣的问题,但我不确定如何解决它。我将仅向您展示问题的两个部分作为示例。

问题是我们要输入13到15位数之间的数字。 然后从那个号码我们删除最后一个号码。如19283828382133应该输出完全相同的数字,而不是最终的3,1928382838213。

然后,这些数字中的每个奇数位(不是数字)都会加倍。所以你会得到2,9,4,8​​,6等

到目前为止,这是我的代码。从代码中可以看出,我已经能够单独完成这两个部分(工作),但我不确定我会如何将它们加在一起。

lastdigit :: Integer -> Integer -- This Function removes the last number
lastdigit x = x`div`10

doubleOdd (x:xs) = (2*x):(doubleEven xs) -- This function doubles every odd digit not number.
doubleOdd [] = []
doubleEven (x:xs) = x:(doubleOdd xs)
doubleEven [] = []

因此,为了进一步解释我正在尝试构建的程序,首先要完成接收13到15位数字的步骤。然后它将首先删除最后一个数字,然后自动进入下一步加倍每个奇数位(不是数字)。感谢

3 个答案:

答案 0 :(得分:2)

首先,你需要一种方法将一些大数字分成数字。

digits :: Integral x => x -> [x]
digits 0 = []
digits x = digits (x `div` 10) ++ [x `mod` 10]

哪个给你......

Prelude> digits 12345
[1,2,3,4,5]

然后,您可以使用init

删除最后一位数字
Prelude> (init . digits) 12345
[1,2,3,4]

列表中奇数元素的map辅助函数。

mapOdd _ [] = []
mapOdd f (x:[]) = [f x]
mapOdd f (x:y:rest) = f x : y : mapOdd f rest

给你......

Prelude> mapOdd (+10) [1..10]
[11,2,13,4,15,6,17,8,19,10]

还有一个回归大量的功能......

undigits = sum . zipWith (*) [10^n | n <- [0..]] . reverse

导致......

Prelude> undigits [1, 2, 3, 4]
1234

并将它们放在一起

Prelude> undigits . mapOdd (*2) . init . digits $ 12345
2264

特别是在函数式语言中,总是试图通过将解决方案组合成较小的问题来解决问题:)

答案 1 :(得分:1)

缺少的组件是一种将整数分解为数字的方法,并从那里重新构建它。这很简单:

string

然后看起来你需要以两种不同的方式对这些数字进行后处理,但前提是它们与谓词匹配。让我们为此构建一个组合器:

digits:: Int -> [Int]
digits = map (`mod` 10) . takeWhile (/= 0) . iterate (`div` 10)

undigits :: [Int] -> Int
undigits = foldr f 0 where f i r = 10 * r + i

当你想要在奇数位置(从左到右)加倍时,会出现第一种情况。同样微不足道的是,when :: (a -> Bool) -> (a -> a) -> a -> a when p f a = if p a then f a else a 通过增加10的力量来打破一个数字的轻微不便。让我们用每个数字的位置作为前缀:

digits

prefix :: [Int] -> [(Int, Int)] prefix is = let n = length is in zip [n, n-1..1] is 现在可以表示为

doubleOdd

您在评论中提到,当双号溢出时,其数字必须加在一起。这是我所指的第二个案例,也是简单本身:

doubleodd :: [Int] -> [Int]
doubleodd = map (snd . when (odd . fst) (id *** double)) . prefix

这是你的最终节目:

double :: Int -> Int
double = when (>= 10) (sum . digits) . (* 2)

...假设“13到15位之间”部分单独验证。

答案 2 :(得分:0)

我希望这会有所帮助,并意识到它可以清理很多。列表索引从0开始,它也是偶数和列表的第一个元素。列表理解过程0,2,4 ......第1,第2和第3项。

let f n = [mod n 10] ++ f (div n 10)
let r = [if even i then d*2 else d|(i,d)<-zip [0..] (init.reverse.take 14.f$19283828382133)]
sum [b*(10^a)|(a,b) <- zip [12,11..0] r]

2948684868416

如果你想要它处理任何长度的数字,这里最简单的方法是length $ show 19283828382133,但我确实有一个功能可以做到这一点。将长度用作3个位置的值,在合成中的take函数中使用全值。