@@ -10,7 +10,7 @@
10Hoon has the usual program control branches. It also has the usual logical
10Hoon has the usual program control branches. It also has the usual logical
11operators: AND `?&`, OR `?|`, and NOT `?!`. It also has a `?=` rune that tests
11operators: AND `?&`, OR `?|`, and NOT `?!`. It also has a `?=` rune that tests
12whether a value matches a given type. In the course of type inference, Hoon
12whether a value matches a given type. In the course of type inference, Hoon
13−learns from `?=` tests in the test condition of [`?:` ("wutcol")](./col/)
13+learns from `?=` tests in the test condition of [`?:` ("wutcol")](#wutcol)
14expressions.
14expressions.
16## Overview
16## Overview
@@ -23,9 +23,9 @@ type for the branches of the `?:`. Branch inference also works
23for expressions which expand to `?:`.
23for expressions which expand to `?:`.
25The test does not have to be a single `?=`; the compiler can
25The test does not have to be a single `?=`; the compiler can
26−analyze arbitrary boolean logic ([`?&` ("wutpam")](./pam/),
26+analyze arbitrary boolean logic ([`?&` ("wutpam")](#wutpam),
27−[`?|` ("wutbar")](./bar/), [`?!` ("wutzap")](./zap/)) with full
27+[`?|` ("wutbar")](#wutbar), [`?!` ("wutzap")](#wutzap)) with full
28−short-circuiting. Equality tests ([`.=` ("dottis")](../dot/tis/)) are *not*
28+short-circuiting. Equality tests ([`.=` ("dottis")](docs/reference/hoon-expressions/rune/dot#tis/)) are *not*
31If the compiler detects that the branch is degenerate (only one
31If the compiler detects that the branch is degenerate (only one
@@ -33,4 +33,577 @@ side is taken), it fails with an error.
36−;list(datapreview "true", classname "runes");
36+;=
38+ ;div(id "wutban"): ?> "wutban"
42+`[%wtbn p=hoon q=hoon]`: positive assertion.
56+`?>` is used to force a crash when some condition `p` doesn't yield 'yes', `%.y`.
58+It can be used for type inference, with the `?=` rune, to specify the type of a value.
80+ ;div(id "wutbar"): ?> "wutbar"
84+`[%wtbr p=(list hoon)]`: logical OR.
88+*Pseudocode*: `a`, `b`, `c`, ... as elements of `p`:
91+?:(a & ?:(b & ?:(c & ?:(... ?:(z & |)))))
109+Irregular: `|(foo bar baz)` is `?|(foo bar baz)`.
114+~zod:dojo> |(=(6 42) =(42 42))
117+~zod:dojo> |(=(6 42) =(42 43))
123+ ;div(id "wutcol"): ?: "wutcol"
127+`[%wtcl p=hoon q=hoon r=hoon]`: branch on a boolean test.
131+If `p` produces yes, `%.y`, then `q`. If `p` produces no, `%.n`, then `r`.
132+If `p` is not a boolean, compiler yells at you.
136+The subject types of `q` and `r` are constrained to match any pattern-matching algebra in `p`. The analysis, which is conservative, understands any combination of [`?=`](#wuttis), [`?&`](#wutpad), [`?|`](#wutbar), and [`?!`](#wutzap), and infers the type of the subject appropriately when compiling.
138+If test analysis reveals that either branch is never taken, or if `p` is not a boolean, compilation fails. An untaken branch is indicated with `mint-lost`.
146+Short-circuiting in boolean tests works as you'd expect
147+and includes the expected inference. For instance,
148+if you write `?&(a b)`, `b` is only executed if `a` is
149+positive, and compiled with that assumption.
151+Note also that all other branching expressions reduce to `?:`.
156+~zod:dojo> ?:((gth 1 0) 3 4)
159+~zod:dojo> ?: (gth 1 0)
164+~zod:dojo> ?:((gth 1 2) 3 4)
167+~zod:dojo> ?: (gth 1 2)
175+ ;div(id "wutdot"): ?. "wutdot"
179+`[%wtdt p=hoon q=hoon r=hoon]`: branch on a boolean test, inverted.
193+`?.` is just like `?:`, but with its last two subexpressions reversed.
195+As is usual with inverted forms, use `?.` when the yes-case expression is much taller and/or wider than the no-case expression.
200+~zod:dojo> ?.((gth 1 2) 3 4)
203+~zod:dojo> ?.(?=(%a 'a') %not-a %yup)
207+ 'this false case is less heavy than the true case'
209+ 'two not equal to 3'
210+ 'but see how \'r is much heavier than \'q?'
211+'but see how \'r is much heavier than \'q?'
216+ ;div(id "wuthep"): ?- "wuthep"
220+`[%wthp p=wing q=(list (pair spec value))]`: switch against a union, with no default.
224+*Pseudocode*: `a`, `b`, `c`, ... as elements of `q`:
247+Regular: *1-fixed*, then *jogging*.
251+The `?-` rune is for a conditional expression in which the type of `p` determines which branch is taken. Usually the type of `p` is a union of other types. There is no default branch.
253+The compiler makes sure that your code neither misses a case of
254+the union, nor includes a double case that isn't there. This is
255+not special handling for `?-`, just a consequence of the
256+semantics of `?:`, which `?-` reduces to.
258+A missing case will throw the `mint-lost` error. An extra case
259+will throw `mint-vain`.
264+~zod:dojo> =cor |= vat=?(%a %b)
282+ ;div(id "wutket"): ?^ "wutket"
286+`[%wtkt p=wing q=hoon r=hoon]`: branch on whether a wing
287+of the subject is a cell.
301+The type of the wing, `p`, must not be known to be either an atom or a cell, or else you'll get a `mint-vain` error at compile time. `mint-vain` means that one of the `?^` branches, `q` or `r`, is never taken.
310+~zod:dojo> ?^(`*`0 1 2)
313+~zod:dojo> ?^(`*`[1 2] 3 4)
319+ ;div(id "wutled"): ?< "wutled"
326+`[%wtgl p=hoon q=hoon]`: negative assertion.
340+`?<` is used to force a crash when some condition `p` doesn't yield 'no', `%.n`.
342+It can be used for type inference with the `?=` rune, much like the `?>` rune.
364+ ;div(id "wutlus"): ?+ "wutlus"
368+`[%wtls p=wing q=hoon r=(list (pair spec hoon))]`: switch against
369+a union, with a default.
373+*Pseudocode*: `a`, `b`, `c`, ... as elements of `r`:
396+Regular: *2-fixed*, then *jogging*.
400+The `?+` rune is for a conditional expression in which the type of `p` determines which branch is taken. Usually the type of `p` is a union of other types. If `p`'s type doesn't match the case for any given branch, the default expression, `q`, is evaluated.
402+If there is a case that is never taken you'll get a `mint-vain` error.
407+~zod:dojo> =cor |= vat=?(%a %b)
425+ ;div(id "wutpad"): ?& "wutpad"
429+`[%wtpd p=(list hoon)]`: logical AND.
433+*Pseudocode*: `a`, `b`, `c`, ... as elements of `p`:
436+?.(a | ?.(b | ?.(c | ?.(... ?.(z | &)))))
454+Irregular: `&(foo bar baz)` is `?&(foo bar baz)`.
459+~zod:dojo> &(=(6 6) =(42 42))
462+~zod:dojo> &(=(6 7) =(42 43))
468+ ;div(id "wutsig"): ?~ "wutsig"
472+`[%wtsg p=wing q=hoon r=hoon]`: branch on whether a wing of the subject is null.
486+It's bad style to use `?~` to test for any zero atom. Use it only for a true null, `~`.
493+~zod:dojo> ?~(foo 1 2)
499+ ;div(id "wuttis"): ?= "wuttis"
503+`[%wtts p=spec q=wing]`: test pattern match.
507+`%.y` (yes) if the noun at `q` is in the type of `p`; `%.n` (no) otherwise.
515+`?=` is not as powerful as it might seem. For instance, it
516+can't generate a loop -- you cannot (and should not) use it to
517+test whether a `*` is a `(list @)`. Nor can it validate atomic
520+Patterns should be as weak as possible. Unpack one layer of
521+union at a time. Don't confirm things the type system knows.
523+For example, when matching from a tagged union for the type `[%foo p=@
524+q=[@ @]]`, the appropriate pattern is `[%foo *]`. You have one
525+question, which is whether the head of the noun is `%foo`.
527+A common error is `find.$`, meaning `p` is not a type.
532+~zod:dojo> =bar [%foo %bar %baz]
533+~zod:dojo> ?=([%foo *] bar)
539+ ;div(id "wutvat"): ?@ "wutvat"
543+`[%wtpt p=wing q=hoon r=hoon]`: branch on whether a wing of the subject is an atom.
557+The type of the wing, `p`, must not be known to be either an atom or a cell, or else you'll get a `mint-vain` error at compile time. `mint-vain` means that one of the `?@` branches, `q` or `r`, is never taken.
566+~zod:dojo> ?@(`*`0 1 2)
569+~zod:dojo> ?@(`*`[1 2] 3 4)
575+ ;div(id "wutzap"): ?! "wutzaps"
579+`[%wtzp p=hoon]`: logical NOT.
587+Produces the logical NOT of `p`.
593+Irregular: `!foo` is `?!(foo)`.
598+~zod:dojo> ?!(.=(1 2))
607+~zod:dojo> !(gth 5 6)