|
| 1 | +# Curryst |
| 2 | + |
| 3 | +A Typst package for typesetting proof trees. |
| 4 | + |
| 5 | + |
| 6 | +## Import |
| 7 | + |
| 8 | +You can import the latest version of this package with: |
| 9 | + |
| 10 | +```typst |
| 11 | +#import "@preview/curryst:0.6.0": rule, prooftree, rule-set |
| 12 | +``` |
| 13 | + |
| 14 | +## Basic usage |
| 15 | + |
| 16 | +To display a proof tree, you first need to create a tree, using the `rule` function. Its first argument is the conclusion, and the other positional arguments are the premises. It also accepts a `name` for the rule name, displayed on the right of the bar, as well as a `label`, displayed on the left of the bar. |
| 17 | + |
| 18 | +```typ |
| 19 | +#let tree = rule( |
| 20 | + label: [Label], |
| 21 | + name: [Rule name], |
| 22 | + [Premise 1], |
| 23 | + [Premise 2], |
| 24 | + [Premise 3], |
| 25 | + [Conclusion], |
| 26 | +) |
| 27 | +``` |
| 28 | + |
| 29 | +Then, you can display the tree with the `prooftree` function: |
| 30 | + |
| 31 | +```typ |
| 32 | +#prooftree(tree) |
| 33 | +``` |
| 34 | + |
| 35 | +In this case, we get the following result: |
| 36 | + |
| 37 | + |
| 38 | + |
| 39 | +Proof trees can be part of mathematical formulas: |
| 40 | + |
| 41 | +```typ |
| 42 | +Consider the following tree: |
| 43 | +$ |
| 44 | + Pi quad = quad prooftree( |
| 45 | + rule( |
| 46 | + Pi_1, |
| 47 | + Pi_2, |
| 48 | + phi, |
| 49 | + ) |
| 50 | + ) |
| 51 | +$ |
| 52 | +$Pi$ constitutes a derivation of $phi$. |
| 53 | +``` |
| 54 | + |
| 55 | + |
| 56 | + |
| 57 | +You can specify a rule as the premises of a rule in order to create a tree: |
| 58 | + |
| 59 | +```typ |
| 60 | +#prooftree( |
| 61 | + rule( |
| 62 | + name: $R$, |
| 63 | + rule( |
| 64 | + name: $A$, |
| 65 | + rule( |
| 66 | + $Pi_1$, |
| 67 | + $C_1 or L$, |
| 68 | + ), |
| 69 | + $C_1 or C_2 or L$, |
| 70 | + ), |
| 71 | + rule( |
| 72 | + $Pi_2$, |
| 73 | + $C_2 or overline(L)$, |
| 74 | + ), |
| 75 | + $C_1 or C_2 or C_3$, |
| 76 | + ) |
| 77 | +) |
| 78 | +``` |
| 79 | + |
| 80 | + |
| 81 | + |
| 82 | +As an example, here is a natural deduction proof tree generated with Curryst: |
| 83 | + |
| 84 | + |
| 85 | + |
| 86 | +<details> |
| 87 | + <summary>Show code</summary> |
| 88 | + |
| 89 | + ```typ |
| 90 | + #let ax = rule.with(name: [ax]) |
| 91 | + #let and-el = rule.with(name: $and_e^ell$) |
| 92 | + #let and-er = rule.with(name: $and_e^r$) |
| 93 | + #let impl-i = rule.with(name: $scripts(->)_i$) |
| 94 | + #let impl-e = rule.with(name: $scripts(->)_e$) |
| 95 | + #let not-i = rule.with(name: $not_i$) |
| 96 | + #let not-e = rule.with(name: $not_e$) |
| 97 | +
|
| 98 | + #prooftree( |
| 99 | + impl-i( |
| 100 | + not-i( |
| 101 | + not-e( |
| 102 | + impl-e( |
| 103 | + ax($Gamma tack p -> q$), |
| 104 | + and-el( |
| 105 | + ax($Gamma tack p and not q$), |
| 106 | + $Gamma tack p$, |
| 107 | + ), |
| 108 | + $Gamma tack q$, |
| 109 | + ), |
| 110 | + and-er( |
| 111 | + ax($Gamma tack p and not q$), |
| 112 | + $Gamma tack not q$, |
| 113 | + ), |
| 114 | + $ underbrace(p -> q\, p and not q, Gamma) tack bot $, |
| 115 | + ), |
| 116 | + $p -> q tack not (p and not q)$, |
| 117 | + ), |
| 118 | + $tack (p -> q) -> not (p and not q)$, |
| 119 | + ) |
| 120 | + ) |
| 121 | + ``` |
| 122 | +</details> |
| 123 | + |
| 124 | + |
| 125 | +## Advanced usage |
| 126 | + |
| 127 | +The `prooftree` function accepts multiple named arguments that let you customize the tree: |
| 128 | + |
| 129 | +<dl> |
| 130 | + <dt><code>min-premise-spacing</code></dt> |
| 131 | + <dd>The minimum amount of space between two premises.</dd> |
| 132 | + |
| 133 | + <dt><code>title-inset</code></dt> |
| 134 | + <dd>The amount to extend the horizontal bar beyond the content. Also determines how far from the bar labels and names are displayed.</dd> |
| 135 | + |
| 136 | + <dt><code>stroke</code></dt> |
| 137 | + <dd>The stroke to use for the horizontal bars.</dd> |
| 138 | + |
| 139 | + <dt><code>vertical-spacing</code></dt> |
| 140 | + <dd>The space between the bottom of the bar and the conclusion, and between the top of the bar and the premises.</dd> |
| 141 | + |
| 142 | + <dt><code>min-bar-height</code></dt> |
| 143 | + <dd>The minimum height of the box containing the horizontal bar.</dd> |
| 144 | + |
| 145 | + <dt><code>dir</code></dt> |
| 146 | + <dd>The orientation of the proof tree (either <code>btt</code> or <code>ttb</code>, <code>btt</code> being the default).</dd> |
| 147 | +</dl> |
| 148 | + |
| 149 | +For more information, please refer to the documentation in [`curryst.typ`](curryst.typ). |
| 150 | + |
| 151 | +## Layout Multiple Rules (a simple way) |
| 152 | + |
| 153 | +Here we show a way to typeset multiple rules at one time : |
| 154 | + |
| 155 | + |
| 156 | +<details> |
| 157 | + <summary>Show code</summary> |
| 158 | + |
| 159 | + ```typ |
| 160 | + #let variable = prooftree(rule( |
| 161 | + name: [Variable], |
| 162 | + $Gamma, x : A tack x : A$, |
| 163 | + )) |
| 164 | + #let abstraction = prooftree(rule( |
| 165 | + name: [Abstraction], |
| 166 | + $Gamma, x: A tack P : B$, |
| 167 | + $Gamma tack lambda x . P : A => B$, |
| 168 | + )) |
| 169 | +
|
| 170 | + #let application = prooftree(rule( |
| 171 | + name: [Application], |
| 172 | + $Gamma tack P : A => B$, |
| 173 | + $Delta tack Q : B$, |
| 174 | + $Gamma, Delta tack P Q : B$, |
| 175 | + )) |
| 176 | +
|
| 177 | + #let weakening = prooftree(rule( |
| 178 | + name: [Weakening], |
| 179 | + $Gamma tack P : B$, |
| 180 | + $Gamma, x : A tack P : B$, |
| 181 | + )) |
| 182 | +
|
| 183 | + #let contraction = prooftree(rule( |
| 184 | + label: [Contraction], |
| 185 | + $Gamma, x : A, y : A tack P : B$, |
| 186 | + $Gamma, z : A tack P[x, y <- z]: B$, |
| 187 | + )) |
| 188 | +
|
| 189 | + #let exchange = prooftree(rule( |
| 190 | + label: [Exchange], |
| 191 | + $Gamma, x : A, y: B, Delta tack P : B$, |
| 192 | + $Gamma, y : B, x: A, Delta tack P : B$, |
| 193 | + )) |
| 194 | +
|
| 195 | + #align(center, rule-set( |
| 196 | + variable, |
| 197 | + abstraction, |
| 198 | + application, |
| 199 | + weakening, |
| 200 | + contraction, |
| 201 | + exchange |
| 202 | + )) |
| 203 | + ``` |
| 204 | +</details> |
| 205 | + |
| 206 | + |
| 207 | +The function `rule-set` is very simple and is implemented this way : |
| 208 | + |
| 209 | +```typ |
| 210 | +#let rule-set(column-gutter: 3em, row-gutter: 2em, ..rules) = { |
| 211 | + set par(leading: row-gutter) |
| 212 | + block(rules.pos().map(box).join(h(column-gutter, weak: true))) |
| 213 | +} |
| 214 | +``` |
| 215 | + |
| 216 | +To have more complex layout you can modify this piece of code at your linking. |
| 217 | +However the `curryst` package is not meant right now for layout of arbritary content |
| 218 | +and other packages do it better for more fine grained customization. |
0 commit comments