考虑列出3个数字,其中每个数字指定位置的变化,其值如下变化:
x从零开始,然后增加1到9,然后y做同样的事情,然后z做同样的事情。当他们都是9时,他们重置为零。
我写了以下内容:
ShiftInX :: ShiftBy->ShiftBy
ShiftInX [z,y,9] = ShiftInY [z,y,0]
ShiftInX [z,y,x] = [z,y,x+1]
ShiftInY :: ShiftBy->ShiftBy
ShiftInY [z,9,0] = ShiftInZ [z,0,0]
ShiftInY [z,y,0] = [z,y+1,0]
ShiftInZ :: ShiftBy->ShiftBy
ShiftInZ [9,0,0] = [0,0,0]
ShiftInZ [z,0,0] = [z+1,0,0]
此外,还有3个字符串:
s1 = "ahsgtdfyu"
s2 = "kfhyrdncl"
s3 = "polsedrtd"
给定一个字符串,我想获取给定字符串的每个字符,在s3中找到它,将其移位x,取出该字母并在s2中找到它,将其移位y,取出该字母并在s3中找到它并将其移动z并重新调整角色。 对给定字符串的每个字符执行相同操作。在处理每个字符之前,ShiftBy列表会按照开头所述进行更改。
我编写了一个函数,它将一个字符和一个shiftBy列表作为输入,并返回一个字符作为输出。它找到如上所述的输出字符。 findChar :: String - > Char - > [Int] - >炭
问题:我希望能够为给定字符串的每个字符调用此函数,但不会丢失shiftBy数字的值,以便每个新字符的shiftBy数字增加。 processString :: String - > [Int] - >串
我为此使用了map,但在处理每个characetr后,值都会丢失。
我被告知我必须使用折叠或显式递归。我明白折叠是什么,但不知道如何在这里使用它。有人可以帮忙吗?
非常感谢
答案 0 :(得分:0)
您的描述非常令人困惑。如果我理解正确,你有一种加密方案,其中s1,s2和s3是密钥,ShiftBy列表是一个加密状态,当你通过要加密的字符串时,它会发生变化。
我不明白你的意思是“在s3中找到它,用x移动它”。你的意思是ROT编码?你的意思是找到索引然后添加x来找到下一个字符,绕着末端旋转?你的意思是实际修改密钥吗?
在任何情况下,听起来都是当前字符加密函数的签名
encryptChar :: Char -> ShiftBy -> Char
什么时候应该
encryptChar :: Char -> ShiftBy -> (Char, ShiftBy)
即。它需要返回调整后的加密状态。
或者,不要传递更改的加密状态并在外部修改它,因为它不依赖于字符。
至于折叠,关键是使加密状态成为折叠状态的一部分。这是一种方法:
-- Given:
encryptChar :: Char -> ShiftBy -> Char
adjustShiftState :: ShiftBy -> ShiftBy -- really just an alias of ShiftInX
-- You can fold thus:
encrypt :: String -> String
encrypt msg = fst $ foldr foldOne initialState msg
where initialState = ("", [0, 0, 0])
foldOne ch (encryptedString, shiftState) =
(encryptChar ch shiftState : encryptedString, adjustShiftState shiftState)
换句话说,折叠时,始终保持一对加密字符串和当前的移位状态。在加密的最后,你获取结果字符串并抛弃移位状态。
以上是有效的;但是,它并没有完全符合您的要求,因为它反过来通过字符串。你需要一个左折叠(因为:
的工作方式)有点复杂,而且可能效率较低。 (在剖析显示问题后,可能会使用严格的左折和严格标记的明智应用。)
这是左侧折叠版本:
encrypt msg = fst $ foldl foldOne msg initialState
where initialState = ("", [0, 0, 0])
foldOne (encryptedString, shiftState) ch =
(encryptedString ++ [encryptChar ch shiftState],
adjustShiftState shiftState)
请注意使用列表连接而不是简单的缺点。