Я бы прежде всего переписал некоторые функции. Например. zip alphabet [0 .. length alphabet]
можно заменить на zip alphabet [0..]
, поскольку zip
остановится с того момента, как один из списков будет исчерпан. Использование (!!)
и head
часто не является хорошей практикой, поскольку эти функции не являются полными: если индекс слишком велик или список пуст, (!!)
и head
приведут к ошибке соответственно.
Мы можем определить вспомогательные функции, например, для num2let
:
import Data.Char(chr, ord)
num2let :: Int -> Char
num2let n = chr (n + ord 'a')
здесь num2let
отобразит 0
в 'a'
, 1
в 'b'
и др. c.
let2num
можно сделать аналогичным образом:
import Data.Char(ord)
let2num :: Char -> Int
let2num c = ord c - ord 'a'
Так что теперь мы можем определить caesarCipher
как:
caesarCipher :: Int -> String -> String
caesarCipher n = map (num2let . (`mod 26`) . (n+) . let2num)
Так что будет выглядеть так:
import Data.Char(chr, ord)
num2let :: Int -> Char
num2let n = chr (n + ord 'a')
let2num :: Char -> Int
let2num c = ord c - ord 'a'
caesarCipher :: Int -> String -> String
caesarCipher n = map (num2let . (`mod` 26) . (n+) . let2num)
Приятно то, что здесь вы можете повторно использовать let2num
и num2let
для других функций.
Обычно функции верхнего уровня разделяются с помощью пустая строка и подпись. Это не необходимо , но обычно делает его более удобным для чтения.