ideate
This commit is contained in:
@@ -0,0 +1,500 @@
|
|||||||
|
# Clojure-Typst
|
||||||
|
|
||||||
|
A Clojure-inspired Lisp that compiles to Typst, bringing s-expressions, functional programming, macros, and REPL-driven development to modern typesetting.
|
||||||
|
|
||||||
|
## Dual Mode: Hiccup + Raw Escapes
|
||||||
|
|
||||||
|
Two modes coexist. Use whichever fits the moment.
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
;; HICCUP - when you need programmatic structure
|
||||||
|
[:heading {:level 1} "Title"]
|
||||||
|
|
||||||
|
;; RAW - when you just want to write
|
||||||
|
#t"= Title"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Mixing Freely
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
[;; Hiccup for structured parts
|
||||||
|
[:heading {:level 1} title]
|
||||||
|
|
||||||
|
;; Raw escape for prose-heavy sections
|
||||||
|
#t"
|
||||||
|
This is just regular Typst content. I can write *bold* and _italic_
|
||||||
|
without all the brackets. Much nicer for prose.
|
||||||
|
|
||||||
|
- Bullet one
|
||||||
|
- Bullet two
|
||||||
|
"
|
||||||
|
|
||||||
|
;; Back to hiccup for programmatic stuff
|
||||||
|
[:table {:columns 2}
|
||||||
|
(for [row data]
|
||||||
|
(list (:name row) (:value row)))]
|
||||||
|
|
||||||
|
;; Raw with interpolation
|
||||||
|
#t"The answer is ~(calculate-answer data)."
|
||||||
|
|
||||||
|
;; Nested: raw inside hiccup
|
||||||
|
[:block {:inset "1em" :fill "gray.lighten(90%)"}
|
||||||
|
#t"This is a _sidebar_ with easy formatting."]
|
||||||
|
|
||||||
|
;; Nested: hiccup inside raw
|
||||||
|
#t"
|
||||||
|
= Section
|
||||||
|
|
||||||
|
Here's a dynamic table:
|
||||||
|
~(render-table results)
|
||||||
|
|
||||||
|
And back to prose.
|
||||||
|
"]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Raw Escape Syntax
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
;; Short string
|
||||||
|
#t"= Heading"
|
||||||
|
|
||||||
|
;; Multi-line block
|
||||||
|
#t"
|
||||||
|
Multiple lines
|
||||||
|
of typst content
|
||||||
|
"
|
||||||
|
|
||||||
|
;; Content with quotes (must escape)
|
||||||
|
#t"He said \"hello\" and *left*."
|
||||||
|
```
|
||||||
|
|
||||||
|
### Interpolation Inside Raw
|
||||||
|
|
||||||
|
Using `~()` - the unquote concept from Clojure's syntax-quote:
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
;; Simple expression
|
||||||
|
#t"The value is ~(expr)."
|
||||||
|
|
||||||
|
;; Hiccup expression returns content
|
||||||
|
#t"Click ~([:link {:src url} label]) to continue."
|
||||||
|
|
||||||
|
;; Conditional
|
||||||
|
#t"Status: ~(if done? 'Complete' 'Pending')"
|
||||||
|
|
||||||
|
;; Loop
|
||||||
|
#t"
|
||||||
|
= Items
|
||||||
|
~(for [i items]
|
||||||
|
(str '- ' (:name i) '\n'))
|
||||||
|
"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Hiccup Syntax
|
||||||
|
|
||||||
|
All elements follow standard Hiccup:
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
[:tag {attrs} children...]
|
||||||
|
```
|
||||||
|
|
||||||
|
- **tag**: Element type (keyword)
|
||||||
|
- **attrs**: Optional map of attributes
|
||||||
|
- **children**: Content (strings, nested elements, or expressions)
|
||||||
|
|
||||||
|
### Element Categories
|
||||||
|
|
||||||
|
| Category | Examples | Children |
|
||||||
|
|----------|----------|----------|
|
||||||
|
| Content elements | `heading`, `strong`, `emph`, `block` | Display content |
|
||||||
|
| Source elements | `link`, `image`, `bibliography` | `link` has display text; others have none |
|
||||||
|
| List elements | `list`, `enum`, `table` | Each child = one item/cell |
|
||||||
|
| Container elements | `figure` | Single content child |
|
||||||
|
| Math | `math` | Math expression string |
|
||||||
|
| References | `ref`, `cite` | None |
|
||||||
|
| Code | `raw` | Code string to display |
|
||||||
|
| Rules | `set`, `show` | Configuration |
|
||||||
|
|
||||||
|
### Reserved Attributes
|
||||||
|
|
||||||
|
| Attr | Used by | Purpose |
|
||||||
|
|------|---------|---------|
|
||||||
|
| `:src` | `link`, `image`, `bibliography` | Source URL/path |
|
||||||
|
| `:label` | Any element | Makes element referenceable |
|
||||||
|
| `:caption` | `figure` | Figure caption text |
|
||||||
|
| `:target` | `ref` | Label to reference |
|
||||||
|
| `:keys` | `cite` | Citation key(s) |
|
||||||
|
| `:element` | `set`, `show` | Element type to configure |
|
||||||
|
| `:block` | `math`, `raw` | Display as block (default: inline) |
|
||||||
|
| `:lang` | `raw` | Code language for syntax highlighting |
|
||||||
|
|
||||||
|
### Basic Elements
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
;; Heading
|
||||||
|
[:heading {:level 2} "My Section"]
|
||||||
|
;; => #heading(level: 2)[My Section]
|
||||||
|
|
||||||
|
;; Inline formatting
|
||||||
|
["Hello " [:strong "world"] " and " [:emph "goodbye"]]
|
||||||
|
;; => Hello #strong[world] and #emph[goodbye]
|
||||||
|
|
||||||
|
;; Link
|
||||||
|
[:link {:src "https://typst.app"} "Typst"]
|
||||||
|
;; => #link("https://typst.app")[Typst]
|
||||||
|
|
||||||
|
;; Image
|
||||||
|
[:image {:src "diagram.png" :width "50%"}]
|
||||||
|
;; => #image("diagram.png", width: 50%)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lists and Tables
|
||||||
|
|
||||||
|
Children are direct content, not wrapped in `:item` or `:cell` tags:
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
;; List
|
||||||
|
[:list "First" "Second" "Third"]
|
||||||
|
;; => #list([First], [Second], [Third])
|
||||||
|
|
||||||
|
;; Table
|
||||||
|
[:table {:columns 2}
|
||||||
|
[:strong "Header 1"] [:strong "Header 2"]
|
||||||
|
"Data 1" "Data 2"]
|
||||||
|
;; => #table(columns: 2, [#strong[Header 1]], [#strong[Header 2]], [Data 1], [Data 2])
|
||||||
|
```
|
||||||
|
|
||||||
|
### Figures
|
||||||
|
|
||||||
|
Caption is an attribute; child element is the content:
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
[:figure {:caption "Architecture diagram" :label :fig/arch}
|
||||||
|
[:image {:src "arch.png" :width "80%"}]]
|
||||||
|
;; => #figure(image("arch.png", width: 80%), caption: [Architecture diagram]) <fig:arch>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Math
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
;; Inline math (default)
|
||||||
|
[:math "x^2 + y^2"]
|
||||||
|
;; => $x^2 + y^2$
|
||||||
|
|
||||||
|
;; Block/display math
|
||||||
|
[:math {:block true} "sum_(i=0)^n i"]
|
||||||
|
;; => $ sum_(i=0)^n i $
|
||||||
|
```
|
||||||
|
|
||||||
|
### Code Display
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
;; Inline code
|
||||||
|
[:raw "let x = 1"]
|
||||||
|
;; => `let x = 1`
|
||||||
|
|
||||||
|
;; Code block with language
|
||||||
|
[:raw {:lang "python" :block true} "print('hello')"]
|
||||||
|
;; => ```python print('hello') ```
|
||||||
|
```
|
||||||
|
|
||||||
|
### References and Citations
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
[:ref {:target :fig/arch}] ;; => @fig:arch
|
||||||
|
[:cite {:keys [:smith2020]}] ;; => @smith2020
|
||||||
|
```
|
||||||
|
|
||||||
|
### Document Settings
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
;; Set rules
|
||||||
|
[:set {:element :page :paper "a4" :margin "2cm"}]
|
||||||
|
;; => #set page(paper: "a4", margin: 2cm)
|
||||||
|
|
||||||
|
[:set {:element :text :font "New Computer Modern" :size "11pt"}]
|
||||||
|
;; => #set text(font: "New Computer Modern", size: 11pt)
|
||||||
|
|
||||||
|
;; Show rules
|
||||||
|
[:show {:element :heading}
|
||||||
|
[:set {:element :text :fill "blue"}]]
|
||||||
|
;; => #show heading: set text(fill: blue)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Spacing and Paragraphs
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
[:h "2em"] ;; => #h(2em)
|
||||||
|
[:v "1em"] ;; => #v(1em)
|
||||||
|
[:parbreak] ;; paragraph break
|
||||||
|
[:linebreak] ;; line break within paragraph
|
||||||
|
```
|
||||||
|
|
||||||
|
## Visualization
|
||||||
|
|
||||||
|
Three levels of visualization, all mappable to hiccup.
|
||||||
|
|
||||||
|
### Built-in Shapes
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
[:rect {:width "2cm" :height "1cm" :fill "blue"} "Label"]
|
||||||
|
;; => #rect(width: 2cm, height: 1cm, fill: blue)[Label]
|
||||||
|
|
||||||
|
[:circle {:radius "0.5cm" :fill "green"}]
|
||||||
|
;; => #circle(radius: 0.5cm, fill: green)
|
||||||
|
|
||||||
|
[:line {:start [0 0] :end [100 50] :stroke "2pt"}]
|
||||||
|
;; => #line(start: (0pt, 0pt), end: (100pt, 50pt), stroke: 2pt)
|
||||||
|
|
||||||
|
[:polygon {:fill "yellow"} [0 0] [1 0] [0.5 1]]
|
||||||
|
;; => #polygon(fill: yellow, (0pt, 0pt), (1pt, 0pt), (0.5pt, 1pt))
|
||||||
|
```
|
||||||
|
|
||||||
|
### CeTZ - Canvas Drawing
|
||||||
|
|
||||||
|
For complex custom drawings. Like TikZ for LaTeX.
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
[:cetz/canvas
|
||||||
|
[:cetz/line [0 0] [2 2]]
|
||||||
|
[:cetz/circle [1 1] {:radius 0.5}]
|
||||||
|
[:cetz/rect [0 0] [2 1] {:fill "blue"}]]
|
||||||
|
```
|
||||||
|
|
||||||
|
Compiles to:
|
||||||
|
|
||||||
|
```typst
|
||||||
|
#import "@preview/cetz:0.4.2"
|
||||||
|
|
||||||
|
#cetz.canvas({
|
||||||
|
import cetz.draw: *
|
||||||
|
|
||||||
|
line((0, 0), (2, 2))
|
||||||
|
circle((1, 1), radius: 0.5)
|
||||||
|
rect((0, 0), (2, 1), fill: blue)
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### Fletcher - Diagrams & Flowcharts
|
||||||
|
|
||||||
|
High-level diagram DSL for architecture, flowcharts, state machines.
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
[:fletcher/diagram {:node-stroke "1pt" :spacing "2em"}
|
||||||
|
[:node [0 0] "Start"]
|
||||||
|
[:edge "->"]
|
||||||
|
[:node [1 0] "Process"]
|
||||||
|
[:edge "->"]
|
||||||
|
[:node [2 0] "End"]]
|
||||||
|
```
|
||||||
|
|
||||||
|
Node shapes: `:circle`, `:diamond`, `:pill`, `:hexagon`, `:cylinder`
|
||||||
|
|
||||||
|
Edge styles: `"->"`, `"->>"`, `"--"`, `"<->"`, `"hook->"`
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
;; Flowchart example
|
||||||
|
[:fletcher/diagram {:node-stroke "1pt" :node-fill "white" :spacing "3em"}
|
||||||
|
[:node [0 0] "Start" {:shape :pill}]
|
||||||
|
[:node [0 1] "Input Data"]
|
||||||
|
[:node [0 2] "Valid?" {:shape :diamond}]
|
||||||
|
[:node [1 2] "Error" {:fill "red.lighten(80%)"}]
|
||||||
|
[:node [0 3] "Process"]
|
||||||
|
[:node [0 4] "End" {:shape :pill}]
|
||||||
|
|
||||||
|
[:edge [0 0] [0 1] "->"]
|
||||||
|
[:edge [0 1] [0 2] "->"]
|
||||||
|
[:edge [0 2] [1 2] "->" {:label "no"}]
|
||||||
|
[:edge [0 2] [0 3] "->" {:label "yes"}]
|
||||||
|
[:edge [1 2] [0 1] "->" {:bend -40}]
|
||||||
|
[:edge [0 3] [0 4] "->"]]
|
||||||
|
```
|
||||||
|
|
||||||
|
### DSL Helpers
|
||||||
|
|
||||||
|
Build higher-level abstractions:
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
(defn service [id name & {:keys [x y color] :or {color "white"}}]
|
||||||
|
[:node [x y] name {:id id :shape :pill :fill color}])
|
||||||
|
|
||||||
|
(defn database [id name & {:keys [x y color] :or {color "gray.lighten(80%)"}}]
|
||||||
|
[:node [x y] name {:id id :shape :cylinder :fill color}])
|
||||||
|
|
||||||
|
(defn connects [from to & {:keys [label style] :or {style "->"}}]
|
||||||
|
[:edge from to style (when label {:label label})])
|
||||||
|
|
||||||
|
[:fletcher/diagram {:spacing "3em"}
|
||||||
|
(service :auth "Auth" :x 0 :y 0)
|
||||||
|
(service :users "Users" :x 1 :y 0)
|
||||||
|
(database :pg "PostgreSQL" :x 0 :y 1)
|
||||||
|
(database :redis "Redis" :x 1 :y 1 :color "red.lighten(80%)")
|
||||||
|
|
||||||
|
(connects :auth :pg)
|
||||||
|
(connects :users :redis :label "cache")]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Macros
|
||||||
|
|
||||||
|
It's a Lisp - of course we have macros.
|
||||||
|
|
||||||
|
### Content Macros
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
;; Define a reusable content pattern
|
||||||
|
(defmacro defcomponent [name args & body]
|
||||||
|
`(defn ~name ~args
|
||||||
|
(list ~@body)))
|
||||||
|
|
||||||
|
;; Conditional content sections
|
||||||
|
(defmacro when-content [test & body]
|
||||||
|
`(when ~test
|
||||||
|
(list ~@body)))
|
||||||
|
|
||||||
|
;; Use it
|
||||||
|
(when-content show-abstract?
|
||||||
|
[:heading {:level 2} "Abstract"]
|
||||||
|
abstract-text)
|
||||||
|
```
|
||||||
|
|
||||||
|
### DSL Macros
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
;; Math DSL
|
||||||
|
(defmacro math-block [& exprs]
|
||||||
|
`[:math {:block true}
|
||||||
|
~(compile-math-dsl exprs)])
|
||||||
|
|
||||||
|
(math-block
|
||||||
|
(sum :i 0 :n
|
||||||
|
(frac (pow x i) (factorial i))))
|
||||||
|
;; => $ sum_(i=0)^n x^i / i! $
|
||||||
|
|
||||||
|
;; Shorthand for references
|
||||||
|
(defmacro ref [id]
|
||||||
|
`[:ref {:target ~id}])
|
||||||
|
|
||||||
|
(defmacro cite [& keys]
|
||||||
|
`[:cite {:keys [~@keys]}])
|
||||||
|
|
||||||
|
(ref :fig/arch) ; => [:ref {:target :fig/arch}]
|
||||||
|
(cite :smith2020 :jones2021) ; => [:cite {:keys [:smith2020 :jones2021]}]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Template Macros
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
(deftemplate ieee-paper [title authors abstract]
|
||||||
|
[[:set {:element :page :paper "us-letter" :columns 2}]
|
||||||
|
[:heading {:level 1 :align "center"} ~title]
|
||||||
|
(render-authors ~authors)
|
||||||
|
(render-abstract ~abstract)
|
||||||
|
~'&body])
|
||||||
|
|
||||||
|
(ieee-paper
|
||||||
|
"Neural Networks for Fun and Profit"
|
||||||
|
[{:name "Alice" :affil "MIT"}]
|
||||||
|
"We present..."
|
||||||
|
|
||||||
|
[:heading {:level 2} "Introduction"]
|
||||||
|
"..."
|
||||||
|
[:heading {:level 2} "Methods"]
|
||||||
|
"...")
|
||||||
|
```
|
||||||
|
|
||||||
|
## Full Example
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
(ns my-paper.core
|
||||||
|
(:require [clojure-typst.core :refer :all]))
|
||||||
|
|
||||||
|
(def authors
|
||||||
|
[{:name "Alice Chen" :affiliation "MIT" :email "alice@mit.edu"}
|
||||||
|
{:name "Bob Smith" :affiliation "Stanford" :email "bob@stanford.edu"}])
|
||||||
|
|
||||||
|
(def results
|
||||||
|
[{:method "Baseline" :accuracy 0.72}
|
||||||
|
{:method "Ours" :accuracy 0.94}])
|
||||||
|
|
||||||
|
(defn author-card [{:keys [name affiliation email]}]
|
||||||
|
[:block {:inset "1em"}
|
||||||
|
[:strong name] [:linebreak]
|
||||||
|
[:emph affiliation] [:linebreak]
|
||||||
|
[:link {:src (str "mailto:" email)} email]])
|
||||||
|
|
||||||
|
(defn results-table [data]
|
||||||
|
[:table {:columns 2 :align ["left" "right"]}
|
||||||
|
[:strong "Method"] [:strong "Accuracy"]
|
||||||
|
(for [{:keys [method accuracy]} data]
|
||||||
|
(list
|
||||||
|
method
|
||||||
|
(format "%.1f%%" (* 100 accuracy))))])
|
||||||
|
|
||||||
|
(def paper
|
||||||
|
[[:set {:element :page :paper "a4"}]
|
||||||
|
[:set {:element :text :font "Linux Libertine"}]
|
||||||
|
|
||||||
|
[:heading {:level 1} "A Very Important Paper"]
|
||||||
|
|
||||||
|
[:block {:align "center"}
|
||||||
|
(interpose [:h "2em"]
|
||||||
|
(map author-card authors))]
|
||||||
|
|
||||||
|
#t"
|
||||||
|
= Abstract
|
||||||
|
|
||||||
|
We present a novel approach to solving important problems.
|
||||||
|
Our method achieves *state-of-the-art* results on several
|
||||||
|
benchmarks while maintaining computational efficiency.
|
||||||
|
|
||||||
|
= Introduction
|
||||||
|
|
||||||
|
The problem of _important things_ has long challenged researchers.
|
||||||
|
Previous approaches @citation1 @citation2 have made progress but
|
||||||
|
fundamental limitations remain.
|
||||||
|
"
|
||||||
|
|
||||||
|
[:figure {:caption "System architecture overview." :label :fig/arch}
|
||||||
|
[:image {:src "architecture.png" :width "80%"}]]
|
||||||
|
|
||||||
|
#t"
|
||||||
|
Our method works by first processing the input through
|
||||||
|
the encoder (see @fig:arch).
|
||||||
|
|
||||||
|
= Results
|
||||||
|
"
|
||||||
|
|
||||||
|
(results-table results)
|
||||||
|
|
||||||
|
#t"
|
||||||
|
As shown in the table above, our method significantly
|
||||||
|
outperforms the baseline.
|
||||||
|
|
||||||
|
= Conclusion
|
||||||
|
|
||||||
|
We have demonstrated that our approach is ~(if (> (:accuracy (last results)) 0.9)
|
||||||
|
\"highly effective\"
|
||||||
|
\"somewhat effective\").
|
||||||
|
"
|
||||||
|
|
||||||
|
[:bibliography {:src "refs.bib"}]])
|
||||||
|
|
||||||
|
(compile-to-typst paper "paper.typ")
|
||||||
|
```
|
||||||
|
|
||||||
|
## Rules Summary
|
||||||
|
|
||||||
|
1. **`#t"..."`** - raw Typst content, returned as-is
|
||||||
|
2. **`~(...)`** inside raw - interpolate Clojure expression
|
||||||
|
3. **`[:tag ...]`** - hiccup, compiled to Typst function calls
|
||||||
|
4. **Strings in hiccup** - become Typst content directly
|
||||||
|
5. **Sequences flatten** - `(for ...)`, `(map ...)`, `(list ...)` results merge into parent
|
||||||
|
|
||||||
|
| Situation | Use |
|
||||||
|
|-----------|-----|
|
||||||
|
| Prose, paragraphs, natural writing | Raw `#t"..."` |
|
||||||
|
| Tables, figures, structured layout | Hiccup |
|
||||||
|
| Loops, conditionals, data-driven | Hiccup or interpolated raw |
|
||||||
|
| Components, reusable parts | Hiccup functions |
|
||||||
|
|
||||||
|
**The principle:** Structure when you need it, prose when you don't.
|
||||||
+3
-13
@@ -50,7 +50,7 @@ Both systems coexist. Use whichever fits the moment.
|
|||||||
"]
|
"]
|
||||||
```
|
```
|
||||||
|
|
||||||
## Escape Syntax Options
|
## Escape Syntax
|
||||||
|
|
||||||
```clojure
|
```clojure
|
||||||
;; Short string
|
;; Short string
|
||||||
@@ -62,18 +62,8 @@ Multiple lines
|
|||||||
of typst content
|
of typst content
|
||||||
"
|
"
|
||||||
|
|
||||||
;; Triple-quote for content with quotes
|
;; Content with quotes (must escape)
|
||||||
#t"""
|
#t"He said \"hello\" and *left*."
|
||||||
He said "hello" and *left*.
|
|
||||||
"""
|
|
||||||
|
|
||||||
;; With explicit delimiters (if we need)
|
|
||||||
#typst{
|
|
||||||
Content here with {braces} works fine
|
|
||||||
}
|
|
||||||
|
|
||||||
;; Tagged for syntax highlighting in editors?
|
|
||||||
#typst/content "..."
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Interpolation Inside Raw
|
## Interpolation Inside Raw
|
||||||
|
|||||||
+9
-8
@@ -138,7 +138,8 @@ The result is $x = 42$.
|
|||||||
|
|
||||||
;; Generate content programmatically
|
;; Generate content programmatically
|
||||||
[[:heading "Authors"]
|
[[:heading "Authors"]
|
||||||
(map #(author-block (:name %) (:inst %)) authors)]
|
(for [{:keys [name inst]} authors]
|
||||||
|
(author-block name inst))]
|
||||||
```
|
```
|
||||||
|
|
||||||
## Special Forms for Content
|
## Special Forms for Content
|
||||||
@@ -172,15 +173,15 @@ If hiccup feels too heavy, we could just use Lisp for logic and escape to raw Ty
|
|||||||
(* n (factorial (dec n)))))
|
(* n (factorial (dec n)))))
|
||||||
|
|
||||||
;; Escape to typst content
|
;; Escape to typst content
|
||||||
#typst{
|
#t"
|
||||||
= Results
|
= Results
|
||||||
|
|
||||||
The factorial of 5 is ~(factorial 5).
|
The factorial of 5 is ~(factorial 5).
|
||||||
|
|
||||||
Here's a table of factorials:
|
Here's a table of factorials:
|
||||||
~(for [i (range 1 11)]
|
~(for [i (range 1 11)]
|
||||||
(str "- " i "! = " (factorial i) "\n"))
|
(str \"- \" i \"! = \" (factorial i) \"\\n\"))
|
||||||
}
|
"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Questions
|
## Questions
|
||||||
|
|||||||
Reference in New Issue
Block a user