如何在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))
答案 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]