Haskell中的长乘法

时间:2017-11-15 18:56:40

标签: list haskell recursion multiplication

如何在Haskell中的列表上实现长乘法。这个想法是,如果你有两个数字,让我们说112和13.这些数字可以表示为列表[1,1,2]和[1,3],你想将它们相乘以得到一个清单[1,4,5,6]。我希望以递归方式执行此操作,因为我希望它可以在任何大小列表上工作。我的" functionWhichSumsLists"是一个我稍后将定义的函数,它将逐个元素地添加两个列表。

longMulti l1 [] = p1
longMulti [] l2 = q1
longMulti (li:l1) (lii:l2) = functionWhichSumsLists [li*lii] (0:(longMulti l1 l2))

1 个答案:

答案 0 :(得分:1)

您可以使用模块化算法,而不是使用String来回转换show

toDigits :: Integral a => a -> [a]
toDigits = go [] where
  go acc 0 = acc
  go acc x = let (xs, x') = x `divMod` 10
             in go (x':acc) xs

然后可以使用fromDigits实现foldl

import Data.List (foldl')

fromDigits :: Integral a => [a] -> a
fromDigits = foldl' (\acc x -> acc * 10 + x) 0

或确实与zipWith (*)

-- note: this is significantly slower than above because of the necessary
--       calls to reverse.
fromDigits = sum . reverse . (zipWith (*) [10^i | i <- [0..]]) . reverse

剩下的是乘法本身。但要小心,因为天真的方法在这里不起作用。

terms = [112, 13]
[xs, ys] = map toDigits terms
wrongAnswer = fromDigits $ zipWith (*) xs ys
-- 13
如上所述,

zipWith (*) [1, 1, 2] [1, 3]变为[1*1, 1*3],当你坐下来想象它时,这显然是错误的。那么,我们必须交叉乘以和求和,对吧?

alsoWrong = fromDigits $ answerDigits where
  answerDigits = zipWith (+) [map (*y) xs | y <- ys]
-- 448

这扩展到

zipWith (+) [map (*1) [1, 1, 2], map (*3) [1, 1, 2]]
= zipWith (+) [[1, 1, 2], [3, 3, 6]]
= [(1+3), (1+3), (2+6)]
= [4, 4, 8] -- fromDigits yields 448

这相当于手工操作:

    112
   x 13
   ----
    336
    112  <--- note this should be slid to the left
   ----
    448

因此,我们可以将相似的技术应用于折叠fromDigits到每个术语。

sum $ map fromDigits $ zipWith (\p xs -> map (*p) xs) tens eachProduct where
  tens        = [10^i | i <- [len-1, len-2..0]]
  eachProduct = [map (*y) xs | y <- ys]
  len         = length eachProduct

结束于:

longMultiplication :: Integral a => a -> a -> a
longMultiplication x y = sum . map fromDigits . zipWith mapper tens $ eachProduct where
    xs          = toDigits x
    ys          = toDigits y
    mapper      = (\p xs -> map (*p) xs)
    tens        = [10^i | i <- [len-1, len-2..0]]
    len         = length eachProduct
    eachProduct = [map (*y') xs | y' <- ys]