首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >FP101x实验室2 sumDigits

FP101x实验室2 sumDigits
EN

Stack Overflow用户
提问于 2016-04-10 15:28:06
回答 1查看 80关注 0票数 0

我被困在由Erik教授的关于edX的函数式编程课程的第二实验室。我将复制粘贴在这里的作业:

在本实验室中,您将为信用卡实现一个验证算法。该算法遵循以下步骤: 从最右边开始的每一秒数字值的两倍。将加倍值的数字和原始数字中毫无疑问的数字相加。计算之和的模量除以10。 如果结果等于0,则该数字是有效的。下面是数字4012888888881881上每一步的结果的一个例子。 为了从最右边的数字开始,我们产生了一个反向的数字列表。然后,我们把每秒钟的数字翻两倍。 结果:1,16,8,2,8,16,8,8,16,16,16,2,0,0,8。 我们将上述结果列表的所有数字加在一起。请注意,我们必须再次将列表中的元素拆分为它们的数字(例如16变为1,6)。 结果: 90例。 最后,我们计算了90在10上的模数。 结果: 0。

由于最终值为0,我们知道上面的数字是有效的信用卡号码。如果我们在输入信用卡号码时出错而提供了4012888888881891,那么最后一步的结果是2,证明该数字无效。

我的代码:

代码语言:javascript
运行
复制
toDigits   :: Integer -> [Integer]
toDigits n = if 0 <= n && n <= 10 then [n] else toDigits ((n - n `mod` 10) `quot` 10) ++ [n `mod` 10]

toDigitsRev :: Integer -> [Integer]
toDigitsRev n = reverse (toDigits n)


doubleSecond :: [Integer] -> [Integer]
doubleSecond xs | length xs <= 1                   = xs
                | 1 < length xs  && length xs < 4  = [fst (splitAt 2 xs) !! 0 ,(*2) (fst (splitAt 2 xs) !! 1 )] ++ snd (splitAt 2 xs)
                | otherwise                        = doubleSecond (fst (splitAt 2 xs)) ++ doubleSecond (snd (splitAt 2 xs))


sumDigits :: [Integer] -> Integer
sumDigits xs | xs == []  = 0
             | otherwise = sum (toDigits (head xs)) + sumDigits (tail xs)

isValid :: Integer -> Bool
isValid n | sumDigits (doubleSecond (toDigitsRev n)) `mod` 10 == 0 = True
          | otherwise                                              = False

接下来,他们给出了以下代码:

代码语言:javascript
运行
复制
numValid :: [Integer] -> Integer
numValid xs = sum . map (\_ -> 1) $ filter isValid xs


creditcards :: [Integer]
creditcards = [ 4716347184862961,
                4532899082537349,
                4485429517622493,
                4320635998241421,
                4929778869082405,
                5256283618614517,
                5507514403575522,
                5191806267524120,
                5396452857080331,
                5567798501168013,
                6011798764103720,
                6011970953092861,
                6011486447384806,
                6011337752144550,
                6011442159205994,
                4916188093226163,
                4916699537435624,
                4024607115319476,
                4556945538735693,
                4532818294886666,
                5349308918130507,
                5156469512589415,
                5210896944802939,
                5442782486960998,
                5385907818416901,
                6011920409800508,
                6011978316213975,
                6011221666280064,
                6011285399268094,
                6011111757787451,
                4024007106747875,
                4916148692391990,
                4916918116659358,
                4024007109091313,
                4716815014741522,
                5370975221279675,
                5586822747605880,
                5446122675080587,
                5361718970369004,
                5543878863367027,
                6011996932510178,
                6011475323876084,
                6011358905586117,
                6011672107152563,
                6011660634944997,
                4532917110736356,
                4485548499291791,
                4532098581822262,
                4018626753711468,
                4454290525773941,
                5593710059099297,
                5275213041261476,
                5244162726358685,
                5583726743957726,
                5108718020905086,
                6011887079002610,
                6011119104045333,
                6011296087222376,
                6011183539053619,
                6011067418196187,
                4532462702719400,
                4420029044272063,
                4716494048062261,
                4916853817750471,
                4327554795485824,
                5138477489321723,
                5452898762612993,
                5246310677063212,
                5211257116158320,
                5230793016257272,
                6011265295282522,
                6011034443437754,
                6011582769987164,
                6011821695998586,
                6011420220198992,
                4716625186530516,
                4485290399115271,
                4556449305907296,
                4532036228186543,
                4916950537496300,
                5188481717181072,
                5535021441100707,
                5331217916806887,
                5212754109160056,
                5580039541241472,
                6011450326200252,
                6011141461689343,
                6011886911067144,
                6011835735645726,
                6011063209139742,
                379517444387209,
                377250784667541,
                347171902952673,
                379852678889749,
                345449316207827,
                349968440887576,
                347727987370269,
                370147776002793,
                374465794689268,
                340860752032008,
                349569393937707,
                379610201376008,
                346590844560212,
                376638943222680,
                378753384029375,
                348159548355291,
                345714137642682,
                347556554119626,
                370919740116903,
                375059255910682,
                373129538038460,
                346734548488728,
                370697814213115,
                377968192654740,
                379127496780069,
                375213257576161,
                379055805946370,
                345835454524671,
                377851536227201,
                345763240913232
              ]

你应该运行numValid creditcards,得到94,我得到39。我怀疑我的错误是在sumDigits,但没有真正找到,任何帮助都是非常感谢的。

EN

回答 1

Stack Overflow用户

发布于 2016-04-10 16:21:01

让我们试着找出那些错误。我们将使用QuickCheck测试几个属性。让我们从toDigits的一些属性开始

代码语言:javascript
运行
复制
toDigits_prop n = n >= 0 ==> length (toDigit n) === length (show n)

在一些类似的测试之后,它将失败:

代码语言:javascript
运行
复制
*Main> quickCheck toDigits_prop
*** Failed! Falsifiable (after 24 tests):
10
1 /= 2

这意味着我们在10上只有一位数,而我们最初期望的是两位数。让我们检查一下toDigits10上的结果

代码语言:javascript
运行
复制
*Main> toDigits 10
[10]

啊哈。toDigits上有一个逻辑错误,边界上的行为是错误的,10不是一个数字。因此,将其改为<= 9而不是<= 10。在此之前,让我们简化这个函数,因为有quotRem同时获得提醒和quot

代码语言:javascript
运行
复制
toDigits :: Integer -> [Integer]
toDigits n = case n `quotRem` 10 of
  (0, m) -> [m] -- only one digit was left
  (q, m) -> toDigits q ++ [m]

请注意,此函数有些效率低下,如果同时反转数字,则可以使其更快:

代码语言:javascript
运行
复制
toDigitsRev :: Integer -> Integer
toDigitsRev n = case n `quotRem` 10 of
  (0, m) -> [m]               -- only one digit was left
  (q, m) -> m : toDigitsRev q -- add current digit left

无论哪种方式,让我们检查新版本的toDigits是否有效:

代码语言:javascript
运行
复制
*Main> quickCheck toDigits_prop
+++ OK, passed 100 tests.

好的。让我们检查一下是否通过了所有测试:

代码语言:javascript
运行
复制
*Main> numValid creditcards
94

好像现在一切都好了。所以关键是检查函数的属性。请注意,可以更容易地编写几个函数。

代码语言:javascript
运行
复制
doubleSecond :: Num a => [a] -> [a]
doubleSecond xs = zipWith ($) (cycle [id, (2*)]) xs
-- or
doubleSecond (x:y:xs) = x : 2 * y : doubleSecond xs
doubleSecond xs       = xs

sumDigits :: [Integer] -> Integer
sumDigits xs = sum (concatMap toDigits xs)
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36531658

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档