Ваша главная проблема - правильно заполнить столбцы пробелами. Исходя из этого другого ответа , мы можем определить наши собственные функции заполнения слева и справа, которые принимают желаемую длину, символ заполнения, строку для заполнения и возвращают дополненную строку правильной длины ( или больше, если строка уже длиннее требуемой длины):
lPadWithChar, rPadWithChar :: Int -> Char -> String -> String
lPadWithChar l c s = replicate (l - length s) c ++ s
rPadWithChar l c s = s ++ replicate (l - length s) c
Название вашей функции personToList
немного сбивает с толку, так как занимает список Person
. Это было бы более читабельным как personsToList
. Чтобы показать наши функции заполнения в действии, мы можем рассмотреть форматирование одного Person
, не беспокоясь о рекурсии:
personToString :: Person -> String
personToString (name, _, _, miles) = rPadWithChar 10 ' ' name
++ intercalate "," (map (lPadWithChar 3 ' ' . show) miles)
Обратите внимание, что вам также не нужно связывать второй и третий элементы Person
, так как вы их не используете. Это стандартная практика в Haskell и упрощает, просто посмотрев на первые несколько символов функции, что она использует только элементы name
и miles
.
Наконец, мы имеем дело с рекурсией и многострочным форматированием в отдельной функции, которая принимает [Person]
.
personsToString :: [Person] -> String
personsToString = concat . intersperse "\n" . map personToString
--You only need one \n, right?
Здесь я использовал функции высшего порядка map
и intersperse
для отвода рекурсии, но вы можете легко превратить это в явную рекурсию. Вот оно в действии:
>>> let testData = [("John", 1.76, 63, [5,8,12,7,12,6,9]), ("Hannah", 1.64, 56, [6,9,10,9,5,13,13]), ("Lewis", 1.80, 73, [4,6,2,6,8,4,6])]
>>> putStrLn $ personsToString testData
John 5, 8, 12, 7, 12, 6, 9
Hannah 6, 9, 10, 9, 5, 13, 13
Lewis 4, 6, 2, 6, 8, 4, 6
Исходя из форматирования ваших тестовых данных, я предполагаю, что это из курса. Просто отметьте, что использование кортежей для переноса сложных групп реальной информации очень подвержено ошибкам и затрудняет обслуживание кода. Например, подумайте, что произойдет, если у вас будет требование сделать мили первым элементом кортежа, в результате вы получите полностью сломанный API. Стандартный способ исправить это - использовать синтаксис записи .