了解 Haskell 中的维吉尼亚密码
Understanding Vigenere cipher in Haskell
我无法理解下面代码中到底发生了什么。
特别是递归函数调用和 "ks++[k]" 以及 chr $65。我假设前者用于递归遍历列表,但如果有人能像我 5 岁那样解释我将不胜感激
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
想法是第一个列表中的每个字符 "shifted" 距离由第二个列表中的相应字符确定。但是,第二个列表的长度可能与第一个不同。如果更长,没有问题;您将忽略额外的部分(如基本情况 vig [] k = []
所示)。但是,如果更短,您将希望从头开始。
假设您从调用 vig "horse" "dog"
开始。然后你将按顺序进行以下递归调用:
vig "orse" "ogd"
vig "rse" "gdo"
vig "se" "dog"
vig "e" "ogd"
vig "" "gdo"
encrypt
是实际加密的内容;它 returns 基于消息中的字符 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
,除了不是通过对每个元素应用一个函数从另一个列表构建一个列表,而是通过对每个相应的元素应用一个函数从 两个 列表构建一个列表对元素。此模式预定义为 zipWith
函数。
vig ps ks = zipWith encrypt ps ks -- vig = zipWith encrypt
where encrypt a b = ...
我无法理解下面代码中到底发生了什么。
特别是递归函数调用和 "ks++[k]" 以及 chr $65。我假设前者用于递归遍历列表,但如果有人能像我 5 岁那样解释我将不胜感激
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
想法是第一个列表中的每个字符 "shifted" 距离由第二个列表中的相应字符确定。但是,第二个列表的长度可能与第一个不同。如果更长,没有问题;您将忽略额外的部分(如基本情况 vig [] k = []
所示)。但是,如果更短,您将希望从头开始。
假设您从调用 vig "horse" "dog"
开始。然后你将按顺序进行以下递归调用:
vig "orse" "ogd"
vig "rse" "gdo"
vig "se" "dog"
vig "e" "ogd"
vig "" "gdo"
encrypt
是实际加密的内容;它 returns 基于消息中的字符 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
,除了不是通过对每个元素应用一个函数从另一个列表构建一个列表,而是通过对每个相应的元素应用一个函数从 两个 列表构建一个列表对元素。此模式预定义为 zipWith
函数。
vig ps ks = zipWith encrypt ps ks -- vig = zipWith encrypt
where encrypt a b = ...