好的,所以我在Haskell中有这个代码:
data Bigit = O | I deriving (Show,Eq)
add x y = reverse $ addC O (reverse x) (reverse y)
addC O [] [] = []
addC I [] [] = [I]
addC carry [] r = addC carry [O] r
addC carry l [] = addC carry l [O]
addC carry (left:leftOver) (right:rightOver) = sumBigit :(addC newCarry leftOver
rightOver)
where
(sumBigit,newCarry)
= case (left,right,left) of
(O,O,O) -> (O,O)
(O,I,O) -> (I,O)
(I,O,O) -> (I,O)
(I,I,O) -> (O,I)
(O,O,I) -> (I,O)
(O,I,I) -> (O,I)
(I,O,I) -> (O,I)
(I,I,I) -> (I,I)
我需要弄清楚它意味着什么。到目前为止,我知道它使用bigits和bigits列表作为类型,并且bigit是I(表示1)和O(表示0)。
我发现了add和addC的类型签名:
add :: [Bigit] -> [Bigit] -> [Bigit]
addC :: Bigit -> [Bigit] -> [Bigit] -> [Bigit]
为了帮助我理解,我已经将代码加载到GHCI中,我一直在玩它。例如,我知道如果我告诉它:
add [I,O] [I,O]
它给了我[我,我,O],因为它遵循:
reverse (addC O (reverse x) (reverse y))
reverse (addC O [O,I] [O,I])
但是从这里开始,我很困惑如何找出addC
部分。我有正确的论点:Bigit和两个Bigits列表。但是,我不明白与之匹配的模式。我对“携带”的含义感到很困惑。
有人可以尝试和帮助吗?
答案 0 :(得分:1)
正如在评论中所解释的那样,addC
函数对反向二进制代码进行操作(没有真正原因的名称为Bigits),并且有一个错误,其中携带需要包含在case
中图案。 addC
的许多变体都涵盖了所有可能的输入组合,特别是在递归调用中:
addC O [] [] = []
这是我们用完数字的情况,进位输入为零。这意味着我们不需要添加另一个数字并且可以返回空列表。
addC I [] [] = [I]
当我们用完输入项时,我们有一个遗留物,所以我们用一个数字扩展结果。一旦两个列表都用尽,这些情况中的任何一个都会匹配,并终止递归评估,因为它们不会再次调用addC。
addC carry [] r = addC carry [O] r
这用于拓宽左词,因为右词没有用尽(如果是,早期的模式会与之匹配)。
addC carry l [] = addC carry l [O]
同样,在没有用完左期时扩大正确的期限。
使用所有这些模式,可以保证主要的addC定义有相同的长度列表可供使用,并且携带不会在长度溢出中丢失。它本来可以用不同的方式写成,这样我们只是复制了任一项的左边部分,一旦进位是O而另一个术语是[],但这些模式是详尽的并且终止,这是最重要的。附注是,就该加法器而言,[]是有效的零值。
addC carry (left:leftOver) (right:rightOver) =
sumBigit :(addC newCarry leftOver rightOver)
where (sumBigit,newCarry) = ....
这是功能的核心。它从左右各个项中提取一个Bigit,并使用真值表计算这些和进位的两位总和(好吧,如果它没有错误,它会的话)。结果保持该总和的最低有效位,然后保持两个项的其余部分与新进位值的递归和。
作为练习,我冒昧地使用foldr
来编写相同的概念。结果不是很漂亮,但确实避免了逆转步骤;排列不同长度的列表需要一个单独的扩展步骤,我通过测量列表的长度来完成。
extMatch :: a -> b -> [a] -> [b] -> [(a,b)]
extMatch a0 b0 a b = zip (ext a0 (lb-la) a) (ext b0 (la-lb) b)
where ext x0 l x | l>0 = concat [replicate l x0, x]
| l<=0 = x
la = length a
lb = length b
add2 :: [Bigit] -> [Bigit] -> [Bigit]
add2 x y = extsum $ foldr addC2 (O, []) (extMatch O O x y)
where extsum (O,sum) = sum
extsum (I,sum) = I:sum
addC2 :: (Bigit, Bigit) -> (Bigit, [Bigit]) -> (Bigit, [Bigit])
addC2 (O, O) (O, sumbits) = (O, O:sumbits)
addC2 (O, O) (I, sumbits) = (O, I:sumbits)
addC2 (O, I) (O, sumbits) = (O, I:sumbits)
addC2 (O, I) (I, sumbits) = (I, O:sumbits)
addC2 (I, O) (O, sumbits) = (O, I:sumbits)
addC2 (I, O) (I, sumbits) = (I, O:sumbits)
addC2 (I, I) (O, sumbits) = (I, O:sumbits)
addC2 (I, I) (I, sumbits) = (I, I:sumbits)