我在理解下面代码中到底发生了什么时遇到了麻烦。
特别是递归函数调用和“ ks ++ [k]”以及chr $ 65。非常感谢。
vig (p:ps) (k:ks) = (encrypt p k):(vig ps (ks++[k]))
where
encrypt b = chr $ 65 + mod (ord a + ord b) 26
完整代码
vig :: [Char] -> [Char] -> [Char]
vig [] k = []
vig p [] = []
vig (p:ps) (k:ks) = (encrypt p k):(vig ps (ks++[k]))
where
encrypt a b = chr $ 65 + mod (ord a + ord b) 26
这个想法是,第一列表中的每个字符都会“移动”一段距离,该距离由第二列表中的相应字符确定。但是,第二个列表的长度可能与第一个列表不同。如果更长,那就没问题了。您将只忽略多余的内容(如基本情况vig [] k = []
所示)。但是,如果它是shorter,则需要从头开始。
假设您从呼叫vig "horse" "dog"
开始。然后,您将按顺序进行以下递归调用:
vig "orse" "ogd"
vig "rse" "gdo"
vig "se" "dog"
vig "e" "ogd"
vig "" "gdo"
encrypt
是实际的加密;它基于消息中的字符p
和加密k
中的字符k
返回一个新字符。每个消息字符仅使用一次;每个键字符可以多次使用(如果键短于消息),或者根本不使用(如果键长于消息)。
一种更简单(更有效的方法)是使用cycle
函数从键创建一个无限的重复列表。 (如果ks
已经足够长,那么它会列出甚至更长的字符,而您最终将忽略这些字符。由于Haskell是惰性的,因此简化抽象没有任何成本。)
vig ps ks = vig' ps (cycle ks)
where vig' _ [] = p
vig' [] _ = []
vig' (p:ps) (k:ks) = encrypt p k : vig' ps ks
encrypt a b = ...
但是,vig'
并不真正在乎列表的内容或encrypt
的内容。有点像map
,除了不是通过对每个元素应用一个函数从另一个列表中构建一个列表,而是通过对每个对应的元素对应用一个函数来从two列表中构建一个列表。此模式预定义为zipWith
功能。
vig ps ks = zipWith encrypt ps ks
where encrypt a b = ...