2010-12-20 12 views
7

Dla klasy Lisp dostaliśmy zadanie domowe z prostym rzędem transpozycji wierszy, które próbowałem rozwiązać również w Haskell. Zasadniczo, jeden po prostu dzieli ciąg znaków na wiersze o długości n, a następnie transponuje wynik. Konkatenacja wynikowej listy list znaków jest zaszyfrowanym łańcuchem. Dekodowanie jest nieco trudniejsze, ponieważ w ostatnim wierszu wejścia mogą wystąpić brakujące elementy (niekompletne kolumny w wyniku), którymi należy się zająć.Szyfrowanie z prostym rzędem

To jest moje rozwiązanie w 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 

spełnia swoje zadanie, ale nie jestem pewien, czy byłoby to uznać za idiomatyczne Haskell, ponieważ mój błahy z indeksów nie czuje się zbyt deklaratywny. Czy można to poprawić, a jeśli tak, to w jaki sposób?

Przy okazji: Czy w Haskell 98 jest coś podobnego do insertAt? To znaczy. funkcja wstawiająca element lub listę z danego indeksu do listy.

Uwaga: NIE jest to częścią zadania domowego, które i tak było dzisiaj należne.

+1

Mała uwaga: możesz pisać 'idxs = [n * rows-1, (n-1) * rows-1 .. (filled + 1) * rows-1]'. – HaskellElephant

+0

@HaskellElephant: Wygląda ładniej, dzięki! – danlei

Odpowiedz

5

Zrobiłbym to, patrząc na problemy encode i decode trochę inaczej. encode dzieli dane na matrycę kolumnową n, którą następnie transponuje (do macierzy scalonej n) i konkatenuje wierszami. decode dzieli dane na macierz wierszy n, którą następnie transponuje (do macierzy kolorów columb n) i łączy się za pomocą wierszy.

tak, że zacznę definiując dwie funkcje: - jedną do tablicy do matrycy n kolumna:

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 

a drugi do krojenia tablicę do matrycy n rzędu:

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 

Teraz kodowanie i dekodowanie jest dość łatwe:

encode :: Int -> [a] -> [a] 
encode = ((concat . transpose) .). chunk 
decode :: Int -> [a] -> [a] 
decode = ((concat . transpose) .). slice 
+0

Dzięki! Mała korekta: Powinien przeczytać fragment "w drugiej straży" chunk ". – danlei

+0

@danlei: thanks! naprawiony. – rampion

+0

'(((concat. Transpose).). Chunk) == (\ x -> \ y -> concat (transpose (fragment x y)))'? – adamse