Almide
Playground
Compile
Run
Source
// Mini Markdown → HTML — ADT + pattern match + pipes + string interp type Block = | Heading(Int, String) | Bullet(String) | Para(String) | Blank fn parse_line(line: String) -> Block = if string.starts_with(line, "### ") then Heading(3, string.drop(line, 4)) else if string.starts_with(line, "## ") then Heading(2, string.drop(line, 3)) else if string.starts_with(line, "# ") then Heading(1, string.drop(line, 2)) else if string.starts_with(line, "- ") then Bullet(string.drop(line, 2)) else if string.is_empty(string.trim(line)) then Blank else Para(line) fn bold(s: String) -> String = string.split(s, "**") |> list.enumerate |> list.map((e) => { let (i, chunk) = e if i % 2 == 1 then "
${chunk}
" else chunk }) |> list.join("") fn render(block: Block) -> String = match block { Heading(n, text) => { let tag = "h" + int.to_string(n) "<${tag}>${bold(text)}${tag}>" } Bullet(text) => "
${bold(text)}
" Para(text) => "
${bold(text)}
" Blank => "" } fn wrap_lists(blocks: List[Block]) -> List[String] = { let result = blocks |> list.fold({ out: [], in_ul: false }, (st, b) => { let is_bullet = match b { Bullet(_) => true, _ => false } let opened = if is_bullet and not st.in_ul then st.out + ["
"] else if not is_bullet and st.in_ul then st.out + ["
"] else st.out { out: opened + [render(b)], in_ul: is_bullet } }) if result.in_ul then result.out + [""] else result.out } fn main() -> Unit = { let md = """ # Almide Playground A **tiny** Markdown to HTML converter in ~50 lines. ## Features - ADT with **variants** - Pattern matching - Pipe-based list ops It's **compact** and **expressive**. """ md |> string.lines |> list.map(parse_line) |> wrap_lists |> list.filter((s) => not string.is_empty(s)) |> list.join("\n") |> println }
Output
Compiled
AST
Press Run to execute.
Anthropic
OpenAI
Gemini
Generate
Your API key is never sent to external servers.
Almide Playground