I am making a markdown to html parser using haskell and this is what i've done so far. Can you spot the issues and fix them?:


module Assignment (markdownParser, convertADTHTML, getTime) where

import           Control.Applicative    (Alternative ((<|>)))
import           Data.Char             (isDigit, isSpace)
import           Data.List             (intersperse)
import           Data.Time.Clock       (getCurrentTime)
import           Data.Time.Format      (defaultTimeLocale, formatTime)
import           Instances             (ParseError (..), ParseResult (..),
                                       Parser (..), readInt)
import           Text.Printf           (printf)

-- Algebraic Data Type (ADT) for Markdown elements
data ADT
  = Paragraph [Inline]
  | Header Int [Inline]
  | AltHeader Int [Inline]
  | Blockquote [Block]
  | CodeBlock (Maybe String) String
  | OrderedList [[Inline]]
  | OrderedSubList [[[Inline]]]
  | Table [[[Inline]]]
  | Image Inline String Inline
  | FootnoteReference Int Inline
  deriving (Show, Eq)


-- ADT for Inline elements (text modifiers, etc.)
data Inline
  = Text String
  | Italic [Inline]
  | Bold [Inline]
  | Strikethrough [Inline]
  | Link String String
  | InlineCode String
  | Footnote Int
  deriving (Show, Eq)


markdownParser :: Parser ADT
markdownParser =  header <|> altHeader <|> blockquote <|> codeBlock <|> image <|> footnoteReference <|> orderedList <|> table <|> paragraph


-- Inline parsers

parseInline :: Parser [Inline]
parseInline = many $ text <|> italic <|> bold <|> strikethrough <|> link <|> inlineCode <|> footnote

text :: Parser Inline
text = Text <$> many (satisfy (/='\n' ))

italic :: Parser Inline
italic = do
  char '_'
  content <- many (text <|> bold <|> strikethrough <|> link <|> inlineCode <|> footnote)
  char '_'
  return $ Italic content

bold :: Parser Inline
bold = do
  string "**"
  content <- many (text <|> italic <|> strikethrough <|> link <|> inlineCode <|> footnote)
  string "**"
  return $ Bold content

strikethrough :: Parser Inline
strikethrough = do
  string "~~"
  content <- many (text <|> italic <|> bold <|> link <|> inlineCode <|> footnote)
  string "~~"
  return $ Strikethrough content

link :: Parser Inline
link = do
  char '['
  linkText <- many (satisfy (/=']'))
  char ']'
  char '('
  url <- many (satisfy (/=')'))
  char ')'
  return $ Link (linkText) (url)


inlineCode :: Parser Inline
inlineCode = do
  char '`'
  code <- many (satisfy (/= '`'))
  char '`'
  return $ InlineCode code


footnote :: Parser Inline
footnote = do
  string "[^"
  num <- readInt
  string "]"
  return $ Footnote num


-- Block parsers
type Block = [Inline]


paragraph :: Parser ADT
paragraph = Paragraph <$> parseInline


header :: Parser ADT
header = do
  hashes <- some (char '#')
  space
  content <- parseInline
  char '\n'
  return $ Header (length hashes) content

altHeader :: Parser ADT
altHeader = do
  content <- parseInline
  char '\n'
  equals <- some (char '=') <|> some (char '-')
  char '\n'
  return $ AltHeader (if head equals == '=' then 1 else 2) content


blockquote :: Parser ADT
blockquote = do
  char '>'
  inlineSpace
  content <- many parseInline `sepBy` (char '\n' >> char '>' >> inlineSpace)
  return $ Blockquote content

codeBlock :: Parser ADT
codeBlock = do
  string "```"
  lang <- optional $ many (satisfy (/= '\n'))
  char '\n'
  code <- many (satisfy (/= '`'))
  string "```"
  char '\n'
  return $ CodeBlock lang code

orderedList :: Parser ADT
orderedList = do
  items <- many1 (orderedListItem <|> orderedSublistItem') `sepBy` char '\n'
  return $ OrderedList (combineListItems items)

orderedListItem :: Parser [Inline]
orderedListItem = do
  _ <- readInt
  char '.'
  inlineSpace
  parseInline

orderedSublistItem' :: Parser [[Inline]]
orderedSublistItem' = do
  string "    "
  _ <- readInt
  char '.'
  inlineSpace
  content <- parseInline
  return [content]

combineListItems :: [[Inline]] -> [[Inline]]
combineListItems = foldr combine []
  where
    combine :: [Inline] -> [[Inline]] -> [[Inline]]
    combine item [] = [[item]]  -- Start a new sublist
    combine item (sublist:sublists) =
      if null sublist  -- Check if the previous sublist is empty
        then (item:sublist):sublists  -- Append to the current sublist
        else [[item]] ++ (sublist:sublists)  -- Create a new sublist if the previous one is not empty


table :: Parser ADT
table = do
  rows <- some tableRow `sepBy1` char '\n'
  return $ Table rows


tableRow :: Parser [[Inline]]
tableRow = cell `sepBy1` char '|'

cell :: Parser [Inline]
cell = do
  inlineSpace
  content <- parseInline -- Keep this content binding for clarity and later processing if needed
  inlineSpace
  return content

image :: Parser ADT
image = do
  char '!'
  char '['
  altText <- parseInline
  char ']'
  char '('
  url <- many (satisfy (/=' ' ))
  inlineSpace
  string "\""
  caption <- parseInline
  string "\""
  char ')'
  return $ Image altText url caption


footnoteReference :: Parser ADT
footnoteReference = do
  string "[^"
  num <- readInt
  string "]"
  char ':'
  inlineSpace
  FootnoteReference num <$> parseInline

-- HTML Conversion
convertADTHTML :: ADT -> String
convertADTHTML adt =
  "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Converted HTML</title>\n</head>\n<body>\n" ++
  convertADT adt ++
  "\n</body>\n</html>"

convertADT :: ADT -> String
convertADT (Paragraph inlines) = "<p>\n    " ++ convertInlines inlines ++ "\n</p>"
convertADT (Header level inlines) = "<h" ++ show level ++ ">\n    " ++ convertInlines inlines ++ "\n</h" ++ show level ++ ">"
convertADT (AltHeader level inlines) = "<h" ++ show level ++ ">\n    " ++ convertInlines inlines ++ "\n</h" ++ show level ++ ">"
convertADT (Blockquote blocks) = "<blockquote>\n" ++ concatMap (\block -> "    <p>\n        " ++ convertInlines block ++ "\n    </p>\n") blocks ++ "</blockquote>"
convertADT (CodeBlock mLang code) = "<pre><code" ++ (case mLang of Just lang -> " class=\"language-" ++ lang ++ "\""; Nothing -> "") ++ ">\n" ++ code ++ "\n</code></pre>"
convertADT (OrderedList items) = "<ol>\n" ++ concatMap (\item -> "    <li>\n        " ++ convertInlines item ++ "\n    </li>\n") items ++ "</ol>"

convertADT (OrderedSubList items) = "<ol>\n" ++ renderList items ++ "</ol>"

renderList :: [[[Inline]]] -> String
renderList = concatMap renderItem
 where 
   renderItem :: [[Inline]] -> String
   renderItem item =
       let topLevel = head item
           subLevels = tail item
           subListHTML = if null subLevels then "" else "        <ol>\n" ++ concatMap (\subItem -> "            <li>\n                " ++ convertInlines subItem ++ "\n            </li>\n" ) (concat subLevels) ++ "        </ol>\n" in
               "    <li>\n         " ++ convertInlines topLevel ++ "\n" ++ subListHTML ++ "    </li>\n"

convertADT (Table rows) = "<table>\n    <thead>\n        <tr>\n            " ++ concatMap (\cell -> "<th>\n                " ++ convertInlines cell ++ "\n            </th>\n            ") (head rows) ++ "        </tr>\n    </thead>\n    <tbody>\n        " ++ concatMap (\row -> "<tr>\n            " ++ concatMap (\cell -> "<td>\n                " ++ convertInlines cell ++ "\n            </td>\n            ") row ++ "        </tr>\n        ") (tail rows) ++ "    </tbody>\n</table>"

convertADT (Image alt url caption) = "<figure>\n    <img src=\"" ++ url ++ "\" alt=\"" ++ convertInlines alt ++ "\">\n    <figcaption>" ++ convertInlines caption ++ "</figcaption>\n</figure>"

convertADT (FootnoteReference num content) = "<p>\n    " ++  convertInlines content ++ "<sup><a href=\"#fn" ++ show num ++ "\" id=\"ref" ++ show num ++ "\">" ++ show num ++ "</a></sup>\n</p>"


convertInlines :: [Inline] -> String
convertInlines = concatMap convertInline


convertInline :: Inline -> String
convertInline (Text str) = str
convertInline (Italic inlines) = "<em>" ++ convertInlines inlines ++ "</em>"
convertInline (Bold inlines) = "<strong>" ++ convertInlines inlines ++ "</strong>"
convertInline (Strikethrough inlines) = "<del>" ++ convertInlines inlines ++ "</del>"
convertInline (Link text url) = "<a href=\"" ++ url ++ "\">" ++ text ++ "</a>"
convertInline (InlineCode code) = "<code>" ++ code ++ "</code>"
convertInline (Footnote num) =  "<sup id=\"fnref"++ show num++"\"><a href=\"#fn"++show num++"\">"++ show num++"</a></sup>"



-- Get current time in ISO 8601 format
getTime :: IO String
getTime = formatTime defaultTimeLocale "%Y-%m-%dT%H:%M:%S" <$> getCurrentTime