对于 Lisp 课程,我们得到了一个简单的行转置密码作业,我也尝试在 Haskell 中解决这个问题。基本上,只需将字符串拆分为长度行n
,然后转置结果。字符列表的结果列表的串联是加密的字符串。解码有点困难,因为输入的最后一行中可能缺少元素(结果中的列不完整),必须注意这些元素。
这是我在 Haskell 中的解决方案:
import Data.List
import Data.Ratio
import Data.List.Split
encode :: String -> Int -> String
encode s n = concat . transpose $ chunk n s
decode :: String -> Int -> String
decode s n = take len $ encode s' rows
where s' = foldr (insertAt " ") s idxs
rows = ceiling (len % n)
idxs = take (n-filled) [n*rows-1,(n-1)*rows-1..]
filled = len - n * (rows - 1)
len = length s
insertAt :: [a] -> Int -> [a] -> [a]
insertAt xs i ys = pre ++ xs ++ post
where (pre,post) = splitAt i ys
它可以完成这项工作,但我不确定这是否会被认为是惯用的 Haskell,因为我对索引的摆弄并不会感觉过于声明性。这可以改进吗?如果可以,如何改进?
insertAt
顺便说一句: Haskell 98 中是否有类似的东西?即将给定索引处的元素或列表插入列表的函数。
注意:这不是家庭作业的一部分,无论如何,这都是今天到期的。