Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 75 additions & 1 deletion content/hoon/rune/ket.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,84 @@ layout:

# ^ ket · Casts

[`^-` ("kethep")](#--kethep), [`^+` ("ketlus")](#-ketlus), and [`^=` ("kettis")](#-kettis) let us adjust types without violating type constraints.
[`^-` ("kethep")](#kethep), [`^+` ("ketlus")](#ketlus), and [`^=` ("kettis")](#kettis) let us adjust types without violating type constraints.

The `+nest` algorithm which tests subtyping is conservative; it never allows invalid nests, it sometimes rejects valid nests.

## ^_ "ketcab" {#ketcab}

Assert that an expression nests in a type, without casting it.

#### Syntax

Two arguments, fixed.

{% tabs %}

{% tab title="Tall form" %}

```hoon
^_ p
q
```

{% endtab %}

{% tab title="Wide form" %}

```hoon
^_(p q)
```

{% endtab %}

{% tab title="Irregular form" %}

None

{% endtab %}

{% endtabs %}

#### AST

```hoon
[%ktcb p=hoon q=hoon]
```

#### Produces

The product of `.q`, with **`.q`'s own type** — not `.p`'s.

#### Discussion

`^_` compiles `.q` using `.p`'s type as the goal, so `.q` must nest in `.p`'s
type or the expression fails to compile. Unlike [`^-`](#kethep), however, the
result keeps the type inferred for `.q`. It is a type *test* rather than a cast.

The difference is visible in the dojo:

```
> ? ^_(*@ 'a')
@t
'a'

> ? ^-(@ 'a')
@
97
```

Both accept `'a'`, because `@t` nests in `@`. `^-` casts the result to `@`, so it
prints as `97`; `^_` leaves it as `@t`, so it prints as `'a'`.

`^_` is what [`=^`](tis.md#tisket) desugars through, which is why that rune
requires its right-hand expression to produce a cell.

Note this rune was spelled `^#` until June 2026; on a kernel from before that
change, use `^#` instead.

---

## ^| "ketbar" {#ketbar}

Convert a gold core to an iron core (contravariant).
Expand Down
14 changes: 14 additions & 0 deletions content/hoon/rune/tis.md
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,20 @@ This may also remind you of Haskell's State monad.

Note that `=^` is subject to the same type nesting limitations as `=.`; e.g., if you have `?~` checked a list for null, you can no longer nest a regular list in the result. (In this case, use a nock `=(~ ...)` equality check instead or recast the result.)

`.r` **must produce a cell.** Since 2026, `=^` desugars through
[`^_`](ket.md#ketcab) with a cell as the goal, so a non-cell right-hand side is a
compile error rather than something that slides through:

```
> =| a=@ =^ b a [1 2] [b a]
[1 2]

> =| a=@ =^ b a 5 [b a]
-need.[* *]
-have.@ud
nest-fail
```

#### Examples

The `+og` core is a stateful pseudo-random number generator. We have to change the core state every time we generate a random number, so we use `=^`:
Expand Down
204 changes: 204 additions & 0 deletions content/hoon/stdlib/2c.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,75 @@ An `$atom`.

***

## `+clz` {#clz}

Leading zeros.

Counts the leading zero bits of `.b` within the block width given by `.a`.

#### Accepts

`.a` is a [`$bite`](1c.md#bite).

`.b` is an `$atom`.

#### Produces

An `$atom`.

#### Source

```hoon
++ clz
~/ %clz
|= [a=bite b=@]
=/ c=[=bloq =step] ?^(a a [a 1])
(sub (mul (bex bloq.c) step.c) (met 0 (end a b)))
```

#### Examples

```
> (clz 3 8)
4
```

---

## `+ctz` {#ctz}

Trailing zeros.

Counts the trailing zero bits of `.a`. Produces `0` for an input of `0`.

#### Accepts

`.a` is an `$atom`.

#### Produces

An `$atom`.

#### Source

```hoon
++ ctz
~/ %ctz
|= a=@
?: =(0 a) 0
=| i=@ud
|-(?:(=(1 (cut 0 [i 1] a)) i $(i +(i))))
```

#### Examples

```
> (ctz 8)
3
```

---

## `+cut` {#cut}

Slice.
Expand Down Expand Up @@ -438,6 +507,99 @@ An `$atom`.

***

## `+ham` {#ham}

Population count.

Counts the set bits of `.a` — the Hamming weight, or popcount.

#### Accepts

`.a` is an `$atom`.

#### Produces

An `$atom`.

#### Source

```hoon
++ ham
~/ %ham
|= a=@
?: =(0 a) 0
=| n=@ud
=/ m (dec (met 0 a))
|- ^- @ud
=? n =(1 (cut 0 [m 1] a))
+(n)
?:(=(0 m) n $(m (dec m)))
```

#### Examples

```
> (ham 255)
8
```

---

## `+hew` {#hew}

Cut many.

Cuts several values out of an atom in sequence, shaped by the argument you apply
the resulting gate to, and reports where it left off.

#### Accepts

`.a` is a [`$bite`](1c.md#bite), the block size and starting offset.

`.c` is an `$atom`, the source.

The product is a wet gate; apply it to a *shape* describing how many blocks each
field should take.

#### Produces

A cell of the filled-in shape and the new `[bloq step]` position.

#### Source

```hoon
++ hew
~/ %hew
|= [a=bite c=@]
=/ d=[=bloq =step] ?^(a a [a 0])
~% %fun +>+ ~
|* b=*
^+ [b d]
?@ b
[(cut bloq.d [step.d b] c) bloq.d (add step.d b)]
=^ f d $(b -.b)
=^ g d $(b +.b)
[[f g] d]
```

#### Examples

Cutting two blocks as one value:

```
> ((hew [3 0] 0xdead.beef) 2)
[48.879 bloq=3 step=2]
```

Cutting two single blocks into a cell:

```
> ((hew [3 0] 0xdead.beef) [1 1])
[[239 190] bloq=3 step=2]
```

---

## `+lsh` {#lsh}

Left-shift.
Expand Down Expand Up @@ -797,6 +959,48 @@ An `$atom`.

***

## `+rig` {#rig}

Convert block sizes.

Re-expresses the step of [`$bite`](1c.md#bite) `.bite` in terms of block size `.b`.

#### Accepts

`.bite` is a [`$bite`](1c.md#bite).

`.b` is a [`$bloq`](1c.md#bloq).

#### Produces

A `+step`.

#### Source

```hoon
++ rig
~/ %rig
|= [=bite b=bloq]
^- step
?@ bite 0
=/ [a=bloq c=step] bite
?: =(a b) c
?: (gth a b)
(lsh [0 (sub a b)] c)
=/ d [0 (sub b a)]
=/ e (rsh d c)
?:(=(0 (end d c)) e +(e))
```

#### Examples

```
> (rig [3 2] 4)
1
```

---

## `+rip` {#rip}

Disassemble.
Expand Down
18 changes: 16 additions & 2 deletions content/hoon/stdlib/4k.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,20 @@ Render as `$tape`.

Renders a `$coin` `.lot` as a `$tape`.

> **Date rendering changed in 2026 (UIP-135).** The month, day, hour, minute and
> second of a `@da`/`@d` are now zero-padded to two digits with `+y-co`, where
> they were previously rendered unpadded with `+a-co`. This changes the *textual*
> output of anything that renders a date, including `(scot %da now)`:
>
> ```
> > (scot %da ~2024.1.2..03.04.05..0006)
> ~.~2024.01.02..03.04.05..0006
> ```
>
> Parsing accepts both forms, so round-tripping is unaffected — but code that
> string-compares rendered dates, or parses them with a strict pattern, may need
> updating.

#### Accepts

`.lot` is a `$coin`, and is the sample of `+co`.
Expand Down Expand Up @@ -161,8 +175,8 @@ A `$tape`.
=. rep ['.' (y-co s.t.yod)]
=. rep ['.' (y-co m.t.yod)]
['.' '.' (y-co h.t.yod)]
=. rep ['.' (a-co d.t.yod)]
=. rep ['.' (a-co m.yod)]
=. rep ['.' (y-co d.t.yod)]
=. rep ['.' (y-co m.yod)]
=? rep !a.yod ['-' rep]
['~' (a-co y.yod)]
::
Expand Down
Loading