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]] -> Stringtable1 = [
[ "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 инсталацията Ви може да стане неизползваема.