Markdown е средтво за писане на свободен текст, в който обикновени символи се използват за форматиране. Поради лесния си и интуитивен синтаксис е широко ползван за форматиране на съобщения във форуми, блогове, GitHub и на много други места.
Целта на текущото упражнение е да се създаде функцията layoutTable
, която подпомага поддържането на добре форматирана таблица. В Markdown таблицатите представляват ASCII art, в който |
се използва като разделител на колона, а ред от -
разделител на заглавната част.
Пример:
| Column 1 | Column 2 |
| ----------------------- | ----------------------- |
| This is cell #1, row #1 | This is cell #2, row #1 |
| This is cell #1, row #2 | This is cell #2, row #2 |
Процесираният Markdown резултат е:
Column 1 | Column 2 |
---|---|
This is cell #1, row #1 | This is cell #2, row #1 |
This is cell #1, row #2 | This is cell #2, row #2 |
Поддържането на големи добре форматирани таблици е пипкава и досадна задача. Затова процедурното им генериране изглежда като най-логичната идея. Функцията layoutTable
прави точно това - тя получава списък от редове (първият е заглавната част (header), а останалите тялото) и връща текста на добре подравнена таблица. Всеки от редовете сам по себе си е списък от клетки (стойностите за съответната колона) [String]
.
layoutTable :: [[String]] -> String
table1 = [
[ "Column 1", "Column 2" ],
[ "This is cell #1, row #1", "This is cell #2, row #1" ],
[ "This is cell #1, row #2", "This is cell #2, row #2" ]
]
> putStr (layoutTable table1)
| Column 1 | Column 2 |
| ----------------------- | ----------------------- |
| This is cell #1, row #1 | This is cell #2, row #1 |
| This is cell #1, row #2 | This is cell #2, row #2 |
Подаденият списък на layoutTable
може да съдържа редове с различен брой колони, а колоните не са предварително подравнени. Това остава задача за функцията - да уравни брой колони в редовете и ширината на клетките в колоната. За улеснение, нека всички колони станат толкова широки, колкото най-широката от тях.
Пример:
table2 = [
[ "Item", "Price" ],
[ "iPhone", "$1", "Not in stock" ],
[ "iPad", "$599" ],
[ "CAUTION: It's a scam!" ]
]
> putStr (layoutTable table2)
| Item | Price | |
| --------------------- | --------------------- | --------------------- |
| iPhone | $1 | Not in stock |
| iPad | $599 | |
| CAUTION: It's a scam! | | |
В Haskell лесно се създават решения, като поредица от стъпки, които трансформират входа. Този подход много прилича на поточна линия или на pipes в Unix. Текущата задача също може да бъде погледната в такава светлина. Фунцкията layoutTable
може да се реализира чрез поредица от следните действия:
- уравняване броя колони (
equalizeColumnCount :: [[String]] -> [[String]]
) - уравняване големината на колоните (
equalizeColumnSize :: [[String]] -> [[String]]
) - добавяне на ред межди заглавието и тялото
- трансформиране на списъка от колони до списък от редове (
toLine :: [String] -> String
) - използване на функцията
unlines
отPrelude
за слепване на списъка от редове доString
Тъй като на много места ни е нужно да "подравняваме" е добре това да го направим с генерализирана функция. Тя трябва да приеме елемент от типа на списъка x :: a
, минимална големина на крайния списък minSize :: Int
и списък xs :: [a]
, който да подравни до исканата големина. Ако подаденият списък е по-голям от minSize
, то той трябва да бъде върнат непроменен.
padWith :: a -> Int -> [a] -> [a]
> padWith 'x' 5 "123"
"123xx"
> padWith 'x' 3 "12345"
"12345"
> padWith "x" 5 ["a", "b", "c" ]
["a", "b", "c", "x", "x" ]
Може да намерите за полезни следните функции:
maximum
- имплементирахме я в упражнението за списъци, връща най-големия елемент от списъкаintercalate
- може да се ползва за слепване масив от низове[String]
с подаденString
> maximum [10, 20, 30]
30
> intercalate " -> " [ "a", "b", "c" ]
"a -> b -> c"
Също както и Lists
това упражнение има тестове. Този път тестовете използват външна библиотека - HSpec. За да инсталирате HSpec
, използвайте cabal
(пакетния мениджър на Haskell).
$ cabal update & cabal install hspec
Пускането на тестовете може да стане по два начина:
$ ghci
> :l MdTableTests.hs
> main
или директно с:
$ runhaskell MdTableTests.hs
Препоръчваме първия вариант.
ВАЖНО: Ако имате проблеми с инсталацията на hspec
, моля потърсете помощ! При оплитане на версиите с cabal
, haskell инсталацията Ви може да стане неизползваема.