8

Lispクラスの場合、Haskellでも解決しようとした単純な行転置暗号の宿題が与えられました。基本的には、文字列を長さの行に分割しn、結果を転置するだけです。結果として得られるcharのリストのリストの連結は、暗号化された文字列です。入力の最後の行(結果の不完全な列)に欠落している要素がある可能性があるため、デコードは少し難しくなります。これらの要素は処理する必要があります。

これは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と見なされるかどうかはわかりません。なぜなら、インデックスをいじるのはあまり宣言的ではないと感じているからです。これは改善できますか?もしそうなら、どのように?

ちなみに、Haskell98に似たものはありinsertAtますか?つまり、特定のインデックスにある要素またはリストをリストに挿入する関数です。

注:これは宿題の一部ではありません。とにかく今日の予定でした。

4

1 に答える 1

6

私は、問題encodedecode問題を少し異なって見ることによってこれを行います。 encodeデータをn-column行列に分割し、次にそれを(n-row行列に)転置し、行ごとに連結します。 decodeデータをn行行列に分割し、次にそれを(列行列にn)転置し、行ごとに連結します。

したがって、2つの関数を定義することから始めます。1つは配列をn列行列にするためのものです。

chunk:: Int -> [a] -> [[a]]
chunk n as = chunk' n (length as) as
  where chunk' n l as | l <= n    = [as]
                      | otherwise = some : chunk' n (l-n) rest 
                          where (some, rest) = splitAt n as

nもう1つは、配列を行マトリックスにスライスします。

slice :: Int -> [a] -> [[a]]
slice n as = chunk (q+1) front ++ chunk q back
  where (q,r) = length as `divMod` n
        (front, back) = splitAt (r*(q+1)) as

現在、エンコードとデコードはかなり簡単です。

encode :: Int -> [a] -> [a]
encode = ((concat . transpose) .). chunk
decode :: Int -> [a] -> [a]
decode = ((concat . transpose) .). slice
于 2010-12-20T19:10:54.057 に答える