Opcode 0: Address#

Syntax#

Opcode 0 implements the idiomatic / fas slot operator, which retrieves a noun at a specified address within the subject.

*[a 0 b]            /[b a]

Before discussing opcode 0, the addressing operator, we need to explore how nouns are structured in Nock.

Nouns#

The fundamental data structure of Nock is the noun, which is either an atom (a non-negative integer) or a cell (an ordered pair of two nouns). Nouns can be visualized as binary trees, in which atoms are leaves and cells are internal nodes.

This leads to a convenient addressing scheme for nouns, for which each noun and sub-noun can be assigned a unique address based on its position in the binary tree. The addressing scheme works as follows:

/[1 a]              a
/[2 a b]            a
/[3 a b]            b
/[(a + a) b]        /[2 /[a b]]
/[(a + a + 1) b]    /[3 /[a b]]
/a                  /a
        %%{init: {'theme':'forest', 'themeVariables': {'defaultLinkColor':'#F5FFF5'}}}%%
flowchart TD
    A(1) --> B
    A(1) --> C
    B(2) --> D
    B(2) --> E
    C(3) --> F
    C(3) --> G
    D(4) --> H
    D(4) --> I
    E(5) --> J
    E(5) --> K
    F(6) --> L
    F(6) --> M
    G(7) --> N
    G(7) --> O
    H(8)
    I(9)
    J(10)
    K(11)
    L(12)
    M(13)
    N(14)
    O(15)
    

That is, the left-hand daughter of a cell is addressed by doubling its mother’s address, while the right-hand daughter is addressed by doubling its mother’s address and adding one. The root of the tree is always at address 1.

Of course, that’s just an addressing scheme: it tells you how a noun is laid out, but not which positions are actually occupied. Let’s see some examples. In these, we will use to denote atoms (leaves) and to denote cells (internal nodes).

[[41 42] [43 44]]#

        %%{init: {'theme':'forest', 'themeVariables': {'defaultLinkColor':'#F5FFF5'}}}%%
flowchart TD
    A(1) --> B
    A(1) --> C
    B(2) --> D
    B(2) --> E
    C(3) --> F
    C(3) --> G
    D{{41}}
    E{{42}}
    F{{43}}
    G{{44}}
    

[1 [2 3]]#

        %%{init: {'theme':'forest', 'themeVariables': {'defaultLinkColor':'#F5FFF5'}}}%%
flowchart TD
    A(1) --> B
    A(1) --> C
    B{{1}}
    C(3) --> D
    C(3) --> E
    D{{2}}
    E{{3}}
    
[a b c]             [a [b c]]

We often omit the right-hand cells since cells tend to branch strongly right in practice. (This saves us from Lisp-style end-paren piles.)

[a b c]             [a [b c]]

Thus, [1 [2 3]] can be written equivalently as [1 2 3].

[[1 2] 3]#

        %%{init: {'theme':'forest', 'themeVariables': {'defaultLinkColor':'#F5FFF5'}}}%%
flowchart TD
    A(1) --> B
    A(1) --> C
    B(2) --> D
    B(2) --> E
    C{{3}}
    D{{1}}
    E{{2}}
    

Syntax (Redux)#

/[1 a]              a
/[2 a b]            a
/[3 a b]            b
/[(a + a) b]        /[2 /[a b]]
/[(a + a + 1) b]    /[3 /[a b]]
/a                  /a

*[a 0 b]            /[b a]

Explanation#

The / fas or slot operator describes how to navigate a noun given an address as an atom. The address is interpreted as a path through the binary tree, starting at the root (address 1). Each even number indicates a left branch, and each odd number indicates a right branch. The process continues until the address 1 is reached, at which point the corresponding noun is returned.

Most of the time, we expand the tree out to the conceptual binary tree map above rather than recursively apply the / fas slot rule.

Opcode 0 is used to retrieve the noun at address b within the subject. b must be a positive atom (the address).

Opcode 0 crashes if the address doesn’t exist (e.g., addressing into an atom). Since there is no address 0, we use /[0 a] or [a 0 0] to denote a crash.

Binary#

Addressing becomes particularly easy to read in binary form, in which a 0 bit corresponds to a left branch and a 1 bit corresponds to a right branch. We ignore the first bit (\(1\), the root) and read the path in binary:

  • \(7_{10} = 111_2 \rightarrow \text{RRR}\).

  • \(5_{10} = 101_2 \rightarrow \text{RLR}\).

  • \(4_{10} = 100_2 \rightarrow \text{RLL}\).

You will notice other patterns, e.g., that the rightmost child at a particular level is equal to a power of 2 minus 1.

Examples#

        %%{init: {'theme':'forest', 'themeVariables': {'defaultLinkColor':'#F5FFF5'}}}%%
flowchart TD
    A(1) --> B
    A(1) --> C
    B(2) --> D{{41}}
    B(2) --> E
    C(3) --> G{{51}}
    C(3) --> H{{52}}
    E(5) --> J{{42}}
    E(5) --> K
    K(11) --> V
    K(11) --> W
    V(22) --> VV{{43}}
    V(22) --> VW{{44}}
    W(23) --> WL
    W(24) --> WR
    WL(46) --> WLL{{45}}
    WL(46) --> WLR{{46}}
    WR(47) --> WRL
    WR(47) --> WRR
    WRL(94) --> WRLL{{47}}
    WRL(94) --> WRLR{{48}}
    WRR(95) --> WRRL{{49}}
    WRR(95) --> WRRR{{50}}
    
:subject [[[41 42 [43 44] [45 46] [47 48] [49 50]]] [51 52]]
Subject set to: [[41 42 [43 44] [45 46] [47 48] 49 50] 51 52]
[0 2]
[41 42 [43 44] [45 46] [47 48] 49 50]
[0 3]
[51 52]
[0 11]
[[43 44] [45 46] [47 48] 49 50]
[0 47]
[[47 48] 49 50]
[0 94]
[47 48]
[0 95]
[49 50]
        %%{init: {'theme':'forest', 'themeVariables': {'defaultLinkColor':'#F5FFF5'}}}%%
flowchart TD
    A(1) --> B{{40}}
    A(1) --> C
    C(3) --> D{{41}}
    C(3) --> E
    E(7) --> F{{42}}
    E(7) --> G
    G(15) --> H{{43}}
    G(15) --> I
    I(31) --> J{{44}}
    I(31) --> K
    K(63) --> L{{45}}
    K(63) --> M
    M(127) --> N{{46}}
    M(127) --> O
    O(255) --> P{{47}}
    O(255) --> Q
    Q(511) --> R{{48}}
    Q(511) --> S
    S(1023) --> T{{49}}
    S(1023) --> U{{50}}
    
:subject [40 41 42 43 44 45 46 47 48 49 50]
Subject set to: [40 41 42 43 44 45 46 47 48 49 50]
[0 2]
40
[0 6]
41
[0 2047]
50