diff --git a/content/hoon/rune/zap.md b/content/hoon/rune/zap.md index d0a0313c..65be502e 100644 --- a/content/hoon/rune/zap.md +++ b/content/hoon/rune/zap.md @@ -426,17 +426,19 @@ None #### Discussion -`.p` is a wing reference like `foo`, `bar.foo`, etc. If `.p` exists, `.q`. If `.p` does not exist, `.r`. Essentially, this is like `?:` for wing existence. +`.p` is a wing reference like `foo`, `bar.foo`, etc. If `.p` does *not* exist, `.q`. If `.p` does exist, `.r`. Essentially, this is like `?:` for wing existence, with the non-existence case first. + +Note the branch order: `.q` is the "missing" branch and `.r` is the "found" branch. This order was reversed in 2025; code written against the previous ordering will compile but take the wrong branch. #### Examples ``` > =foo 42 -> !@(foo 'exists' 'does not exist') +> !@(foo 'does not exist' 'exists') 'exists' -> !@(baz 'exists' 'does not exist') +> !@(baz 'does not exist' 'exists') 'does not exist' ``` diff --git a/content/hoon/stdlib/1b.md b/content/hoon/stdlib/1b.md index 50316dc8..833b72cf 100644 --- a/content/hoon/stdlib/1b.md +++ b/content/hoon/stdlib/1b.md @@ -228,9 +228,9 @@ Specifically, `+peg` just concatenates the bits of the input, excluding the most #### Accepts -`.a` is an `$atom`. +`.a` is an `$atom`. It must be non-zero; `+peg` crashes on `0`. -`.b` is an `$atom`. +`.b` is an `$atom`. It must also be non-zero; `+peg` crashes on `0`. #### Produces @@ -243,6 +243,7 @@ An `$atom`. ~/ %peg |= [a=@ b=@] ?< =(0 a) + ?< =(0 b) ^- @ ?- b %1 a diff --git a/content/hoon/stdlib/2h.md b/content/hoon/stdlib/2h.md index 4074e3e4..d07c2330 100644 --- a/content/hoon/stdlib/2h.md +++ b/content/hoon/stdlib/2h.md @@ -147,10 +147,10 @@ A `$flag`. =| [l=(unit) r=(unit)] |. ^- ? ?~ a & - ?& ?~(l & (gor n.a u.l)) - ?~(r & (gor u.r n.a)) - ?~(l.a & ?&((mor n.a n.l.a) $(a l.a, l `n.a))) - ?~(r.a & ?&((mor n.a n.r.a) $(a r.a, r `n.a))) + ?& ?~(l & &((gor n.a u.l) !=(n.a u.l))) + ?~(r & &((gor u.r n.a) !=(u.r n.a))) + ?~(l.a & ?&((mor n.a n.l.a) !=(n.a n.l.a) $(a l.a, l `n.a))) + ?~(r.a & ?&((mor n.a n.r.a) !=(n.a n.r.a) $(a r.a, r `n.a))) == ``` @@ -267,6 +267,7 @@ A `+set`. ++ del ~/ %del |* b=* + => .(b `_?>(?=(^ a) n.a)`b) |- ^+ a ?~ a ~ diff --git a/content/hoon/stdlib/2i.md b/content/hoon/stdlib/2i.md index ab8f61d9..050f5ad6 100644 --- a/content/hoon/stdlib/2i.md +++ b/content/hoon/stdlib/2i.md @@ -207,15 +207,13 @@ See section [`2f`](2f.md) for more information on `$noun` ordering. Bifurcate. -Splits `+map` `.a` into two `+map`s `.l` and `.r`, which contain the items either side of key `.b` with value `.c` but not including the pair of key `.b` and value `.c`. +Splits `+map` `.a` into two `+map`s `.l` and `.r`, which contain the items either side of key `.b`, not including the item at key `.b`. #### Accepts `.a` is a `+map`, and is the sample of `+by`. -`.b` is a `$noun`. - -`.c` is a `$noun`. +`.b` is a `$noun`, the key to split at. #### Produces @@ -226,23 +224,19 @@ A cell of two `+map`s. ```hoon ++ bif ~/ %bif - |* [b=* c=*] - ^+ [l=a r=a] - =< + - |- ^+ a + |* b=* + |- ^+ [l=a r=a] ?~ a - [[b c] ~ ~] + [~ ~] ?: =(b p.n.a) - ?: =(c q.n.a) - a - a(n [b c]) + +.a ?: (gor b p.n.a) =+ d=$(a l.a) ?> ?=(^ d) - d(r a(l r.d)) + [l.d a(l r.d)] =+ d=$(a r.a) ?> ?=(^ d) - d(l a(r l.d)) + [a(r l.d) r.d] ``` #### Examples @@ -250,10 +244,12 @@ A cell of two `+map`s. ``` > =a (malt `(list [@tas @])`~[a+1 b+2 c+3 d+4 e+5]) -> (~(bif by a) b+2) -[l=[n=[p=%e q=5] l=~ r=~] r=[n=[p=%d q=4] l=~ r=[n=[p=%c q=3] l={[p=%a q=1]} r={}]]] +> (~(bif by a) %b) +[ l=[n=[p=%e q=5] l=~ r=~] + r=[n=[p=%d q=4] l=~ r=[n=[p=%c q=3] l={[p=%a q=1]} r={}]] +] -> `[(map @tas @) (map @tas @)]`(~(bif by a) b+2) +> `[(map @tas @) (map @tas @)]`(~(bif by a) %b) [{[p=%e q=5]} {[p=%d q=4] [p=%a q=1] [p=%c q=3]}] ``` @@ -261,6 +257,21 @@ A cell of two `+map`s. Note that `+map`s are horizontally ordered by the [`+mug`](2e.md#mug) hash of their keys and vertically ordered by the double-`+mug` hash of their keys. This means bifurcating the `+map` `(malt ~[10^10 20^20 30^30 40^40 50^50])` at `30^30` will not produce `[{10^10 20^20} {40^40 50^50}]`, but rather `[{20^20} {10^10 40^40 50^50}]` due to the tree structure resulting from their `+mug` hashes. +`+bif:by` formerly took two arguments, a key `.b` and a value `.c`, and inserted +that pair if it was absent. It now takes the key alone and never inserts. Because +the sample is `b=*`, **calling it the old way does not raise an error** — the two +arguments are passed as the single cell `[b c]`, so the map is split at that cell +rather than at the key, and the item at `.b` is left in the result. Callers written +against the old signature therefore fail silently. For example: + +``` +> `[(map @tas @) (map @tas @)]`(~(bif by a) b+2) +[{[p=%e q=5] [p=%b q=2] [p=%d q=4] [p=%a q=1]} {[p=%c q=3]}] +``` + +The map is split on the noun `[%b 2]`, and `[p=%b q=2]` is still present in the +result rather than having been removed. + --- ### `+del:by` {#delby} @@ -285,6 +296,7 @@ A `+map`. ++ del ~/ %del |* b=* + => .(b `_?>(?=(^ a) p.n.a)`b) |- ^+ a ?~ a ~ @@ -338,23 +350,20 @@ A `+map`. ```hoon ++ dif ~/ %dif - =+ b=a - |@ - ++ $ - |- ^+ a - ?~ b - a - =+ c=(bif p.n.b q.n.b) - ?> ?=(^ c) - =+ d=$(a l.c, b l.b) - =+ e=$(a r.c, b r.b) - |- ^- [$?(~ _a)] - ?~ d e - ?~ e d - ?: (mor p.n.d p.n.e) - d(r $(d r.d)) - e(l $(e l.e)) - -- + |* b=_a + |- ^+ a + ?~ b + a + =+ c=(bif p.n.b) + ?> ?=(^ c) + =+ d=$(a l.c, b l.b) + =+ e=$(a r.c, b r.b) + |- ^- [$?(~ _a)] + ?~ d e + ?~ e d + ?: (mor p.n.d p.n.e) + d(r $(d r.d)) + e(l $(e l.e)) ``` #### Examples diff --git a/content/hoon/stdlib/3d.md b/content/hoon/stdlib/3d.md index 60b196dc..d2a454b1 100644 --- a/content/hoon/stdlib/3d.md +++ b/content/hoon/stdlib/3d.md @@ -130,7 +130,8 @@ Produces an `$atom` by using SHA-256 plus a salt input. The [bitwise XOR](2d.md) ++ shas ~/ %shas |= [sal=@ ruz=@] - (shax (mix sal (shax ruz))) + =/ len (max 32 (met 3 sal)) + (shay len (mix sal (shax ruz))) ``` #### Examples diff --git a/content/hoon/stdlib/4b.md b/content/hoon/stdlib/4b.md index d40c27d1..48b7f75d 100644 --- a/content/hoon/stdlib/4b.md +++ b/content/hoon/stdlib/4b.md @@ -930,26 +930,26 @@ An `$atom`. ## `+trim` {#trim} -Tape split. +List split. -Split first `.a` characters off `$tape` `.b`. +Split first `.a` elements off `+list` `.b`. #### Accepts `.a` is an `$atom`. -`.b` is a `$tape`. +`.b` is a `+list` of any type. #### Produces -A cell of `$tape`s, `.p` and `.q`. +A cell of two `+list`s of the same type as `.b`, `.p` and `.q`. #### Source ```hoon ++ trim - |= [a=@ b=tape] - ^- [p=tape q=tape] + |* [a=@ b=(list)] + ^+ [p=b q=b] ?~ b [~ ~] ?: =(0 a) @@ -962,14 +962,28 @@ A cell of `$tape`s, `.p` and `.q`. ``` > (trim 5 "lasok termun") -[p="lasok" q=" termun"] +[p=[i='l' t="asok"] q=[i=' ' t="termun"]] ``` ``` > (trim 5 "zam") -[p="zam" q=""] +[p=[i='z' t="am"] q=~] ``` +``` +> (trim 2 `(list @ud)`~[1 2 3 4]) +[p=[i=1 t=~[2]] q=[i=3 t=~[4]]] +``` + +#### Discussion + +`+trim` was formerly a dry gate over `$tape` (`|= [a=@ b=tape]`) and is now a +wet gate over `+list`, so it works on a list of any type. One consequence is +that the product is no longer cast to `$tape`, so a tape argument produces a +list that pretty-prints structurally (`[i='l' t="asok"]`) rather than as +`"lasok"`. The value is unchanged; only the inferred type and its printed form +differ. + --- ## `+trip` {#trip} diff --git a/content/hoon/stdlib/4f.md b/content/hoon/stdlib/4f.md index 240e49d4..3d92e978 100644 --- a/content/hoon/stdlib/4f.md +++ b/content/hoon/stdlib/4f.md @@ -432,11 +432,18 @@ A `$rule`. Indentation block. -Apply `$rule` to indented block starting at current column number, omitting the leading whitespace. +Apply `$rule` to a delimited, indented block starting at the current column number, omitting the leading whitespace. #### Accepts -`.sef` is a `$rule`. +`.ope` is a `$rule` matching the block's opening delimiter. + +`.end` is a `$rule` matching the block's closing delimiter. + +`.sef` is a `$rule` applied to the block's contents. + +The first two are passed together as a cell, so the call shape is +`(inde [ope end] sef)`. #### Produces @@ -445,36 +452,56 @@ A `$rule`. #### Source ```hoon -++ inde |* sef=rule - |= nail ^+ (sef) - =+ [har tap]=[p q]:+< +++ inde + |* [[ope=rule end=rule] sef=rule] + |= tub=nail ^+ (sef) + =* har p.tub + =* tap q.tub =+ lev=(fil 3 (dec q.har) ' ') =+ eol=(just `@t`10) - =+ =- roq=((star ;~(pose prn ;~(sfix eol (jest lev)) -)) har tap) - ;~(simu ;~(plug eol eol) eol) + =+ and=;~(plug eol (jest lev) end) + :: get block contents without the indenting spaces + :: + =/ roq + %. tub + =/ led + ;~ pose + ;~(sfix eol (jest lev)) :: eat leading spaces + ;~(simu ;~(plug eol eol) eol) :: allow empty lines + == + ;~ pfix ope led + %- star + ;~(less and ;~(pose prn led)) + == ?~ q.roq roq - =+ vex=(sef har(q 1) p.u.q.roq) + :: parse block contents fully + :: + =+ vex=((full sef) har(q 1) p.u.q.roq) + :: indent hair, produce result, continue after block + :: =+ fur=p.vex(q (add (dec q.har) q.p.vex)) ?~ q.vex vex(p fur) - =- vex(p fur, u.q -) - :+ &3.vex - &4.vex(q.p (add (dec q.har) q.p.&4.vex)) - =+ res=|4.vex - |- ?~ res |4.roq - ?. =(10 -.res) [-.res $(res +.res)] - (welp [`@t`10 (trip lev)] $(res +.res)) + =+ vux=(and p.roq q.q.u.q.roq) + ?~ q.vux vux + [p.vux ~ p.u.q.vex q.u.q.vux] ``` #### Examples ``` -> `tape`(scan " foo\0a bar" ;~(pfix ace ace ace (inde (star ;~(pose prn (just '\0a')))))) +> `tape`(scan "\"\"\"\0afoo\0abar\0a\"\"\"" (inde [(jest '"""') (jest '"""')] (star ;~(pose prn (just `@`10))))) "foo\0abar" ``` #### Discussion -Note the amount of indentation whitespace to be stripped from the beginning of each line is determined by the value of `.q` (the column) in the `$hair` when `+inde` is first called. This means something like the `+pfix` expression in the example above is necessary to set the level of indentation. Additionally, the `$rule` given to `+inde` must consume the whole line including the line ending. +Note the amount of indentation whitespace to be stripped from the beginning of each line is determined by the value of `.q` (the column) in the `$hair` when `+inde` is first called. Additionally, the `$rule` given to `+inde` must consume the whole line including the line ending. + +`+inde` previously took only `.sef` and was called as `(inde sef)`, with the +indentation level established by a preceding `+pfix`. It was rewritten to take +explicit opening and closing delimiters; the one-argument call now fails to +compile with `mull-grow` / `-find.sef`. The kernel uses it this way to parse +`"""` block strings (see `+quote-innards` in `sys/hoon.hoon`). --- diff --git a/content/hoon/stdlib/4i.md b/content/hoon/stdlib/4i.md index e8e6a4f8..2e38016e 100644 --- a/content/hoon/stdlib/4i.md +++ b/content/hoon/stdlib/4i.md @@ -737,11 +737,15 @@ Parse a single hexadecimal digit. Indentation block. -Apply `$rule` to indented block starting at current column number, omitting the leading whitespace. +Apply `$rule` to a delimited, indented block starting at the current column number, omitting the leading whitespace. + +`+iny` is an alias for [`+inde`](4f.md#inde); see there for details. #### Accepts -`sef` is a `$rule` +`.ope` and `.end` are `$rule`s matching the block's opening and closing +delimiters, passed together as a cell; `.sef` is a `$rule` applied to the +contents. The call shape is `(iny [ope end] sef)`. #### Produces @@ -750,31 +754,13 @@ A `$rule`. #### Source ```hoon -++ iny - |* sef=rule - |= nail ^+ (sef) - =+ [har tap]=[p q]:+< - =+ lev=(fil 3 (dec q.har) ' ') - =+ eol=(just `@t`10) - =+ =- roq=((star ;~(pose prn ;~(sfix eol (jest lev)) -)) har tap) - ;~(simu ;~(plug eol eol) eol) - ?~ q.roq roq - =+ vex=(sef har(q 1) p.u.q.roq) - =+ fur=p.vex(q (add (dec q.har) q.p.vex)) - ?~ q.vex vex(p fur) - =- vex(p fur, u.q -) - :+ &3.vex - &4.vex(q.p (add (dec q.har) q.p.&4.vex)) - =+ res=|4.vex - |- ?~ res |4.roq - ?. =(10 -.res) [-.res $(res +.res)] - (welp [`@t`10 (trip lev)] $(res +.res)) +++ iny inde ``` #### Examples ``` -> `tape`(scan " foo\0a bar" ;~(pfix ace ace ace (iny (star ;~(pose prn (just '\0a')))))) +> `tape`(scan "\"\"\"\0afoo\0abar\0a\"\"\"" (iny [(jest '"""') (jest '"""')] (star ;~(pose prn (just `@`10))))) "foo\0abar" ``` diff --git a/content/hoon/stdlib/4n.md b/content/hoon/stdlib/4n.md index 9a494ef6..d151000f 100644 --- a/content/hoon/stdlib/4n.md +++ b/content/hoon/stdlib/4n.md @@ -37,7 +37,7 @@ The `+unit` of a `$noun`. ++ mack |= [sub=* fol=*] ^- (unit) - =/ ton (mink [sub fol] |~(^ ~)) + =/ ton (mink [sub fol] ~) ?.(?=(%0 -.ton) ~ `product.ton) ``` @@ -94,7 +94,19 @@ Note that the gate is expected to return a result of type `(unit (unit))`. A nul `.formula` is the formula as a `$noun`. -`+scry` is an `%iron` gate invoked with Nock operator 12. +`+scry` is either `~`, or an `%iron` gate invoked with Nock operator 12. + +Passing `~` means "no scry handler is available". A formula that never performs a +Nock 12 evaluates normally; one that does immediately produces `[%2 trace]`, the +same block result as an unavailable read. For example: + +``` +> (mink [[1 2] [0 2]] ~) +[%0 product=1] + +> (mink [0 [12 [1 0] [1 0]]] ~) +[%2 trace=~] +``` #### Produces @@ -106,7 +118,7 @@ A `$tone`. ++ mink !. ~/ %mink |= $: [subject=* formula=*] - scry=$-(^ (unit (unit))) + scry=$@(~ $-(^ (unit (unit)))) == =| trace=(list [@ta *]) |^ ^- tone @@ -316,7 +328,7 @@ The `+unit` of a `$noun`. ```hoon ++ mock - |= [[sub=* fol=*] gul=$-(^ (unit (unit)))] + |= [[sub=* fol=*] gul=$@(~ $-(^ (unit (unit))))] (mook (mink [sub fol] gul)) ```