shrub/pub/doc/hoon/library/2c.md
2015-06-19 17:16:48 -04:00

51 KiB

chapter 2c, simple noun surgery

section 2cA, bit surgery

++bex

Binary exponent

++  bex                                                 ::  binary exponent
  ~/  %bex
  |=  a=@
  ^-  @
  ?:  =(0 a)  1
  (mul 2 $(a (dec a)))

Computes the result of 2^a, producing an atom.

a is an atom.

~zod/try=> (bex 4)
16
~zod/try=> (bex (add 19 1))
1.048.576
~zod/try=> (bex 0)
1

++xeb

Binary logarithm

++  xeb                                                 ::  binary logarithm
  ::  ~/  %xeb
  |=  a=@
  ^-  @
  (met 0 a)

Computes the base-2 logarithm of a, producing an atom.

a is an atom.

~zod/try=> (xeb 31)
5
~zod/try=> (xeb 32)
6
~zod/try=> (xeb 49)
6
~zod/try=> (xeb 0)
0
~zod/try=> (xeb 1)
1
~zod/try=> (xeb 2)
2

++can

Assemble

++  can                                                 ::  assemble
  ~/  %can
  |=  [a=bloq b=(list ,[p=@ q=@])]
  ^-  @
  ?~  b  0
  (mix (end a p.i.b q.i.b) (lsh a p.i.b $(b t.b)))

Produces an atom from a list b of length-value pairs p and q, where p is the length in bloqs of size a, and q is an atomic value.

a is a block size (see ++bloq).

b is a list of length value pairs, p and q.

~zod/try=> `@ub`(can 3 ~[[1 1]])
0b1 
~zod/try=> `@ub`(can 0 ~[[1 255]])
0b1
~zod/try=> `@ux`(can 3 [3 0xc1] [1 0xa] ~)
0xa00.00c1
~zod/try=> `@ux`(can 3 [3 0xc1] [1 0xa] [1 0x23] ~)
0x23.0a00.00c1
~zod/try=> `@ux`(can 4 [3 0xc1] [1 0xa] [1 0x23] ~)
0x23.000a.0000.0000.00c1
~zod/try=> `@ux`(can 3 ~[[1 'a'] [2 'bc']])
0x63.6261

++cat

Concatenate

++  cat                                                 ::  concatenate
  ~/  %cat
  |=  [a=bloq b=@ c=@]
  (add (lsh a (met a b) c) b)

Concatenates two atoms, b and c, using bloq size a, producing an atom.

a is a block size (see ++bloq).

b is an atom.

c is an atom.

~zod/try=> `@ub`(cat 3 1 0)
0b1
~zod/try=> `@ub`(cat 0 1 1)
0b11
~zod/try=> `@ub`(cat 0 2 1)
0b110
~zod/try=> `@ub`(cat 2 1 1)
0b1.0001
~zod/try=> `@ub`256
0b1.0000.0000
~zod/try=> `@ub`255
0b1111.1111
~zod/try=> `@ub`(cat 3 256 255)
0b1111.1111.0000.0001.0000.0000
~zod/try=> `@ub`(cat 2 256 255)
0b1111.1111.0001.0000.0000
~zod/try=> (cat 3 256 255)
16.711.936

++cut

Slice

++  cut                                                 ::  slice
  ~/  %cut
  |=  [a=bloq [b=@ c=@] d=@]
  (end a c (rsh a b d))

Slices c blocks of size a that are b blocks from the end of d. Produces an atom.

a is a block size (see ++bloq).

b is an atom.

c is an atom.

~zod/try=> (cut 0 [1 1] 2)
1
~zod/try=> (cut 0 [2 1] 4)
1
~zod/try=> `@t`(cut 3 [0 3] 'abcdefgh')
'abc'
~zod/try=> `@t`(cut 3 [1 3] 'abcdefgh')
'bcd'
~zod/try=> `@ub`(cut 0 [0 3] 0b1111.0000.1101)
0b101
~zod/try=> `@ub`(cut 0 [0 6] 0b1111.0000.1101)
0b1101
~zod/try=> `@ub`(cut 0 [4 6] 0b1111.0000.1101)
0b11.0000
~zod/try=> `@ub`(cut 0 [3 6] 0b1111.0000.1101)
0b10.0001

++end

Tail

++  end                                                 ::  tail
  ~/  %end
  |=  [a=bloq b=@ c=@]
  (mod c (bex (mul (bex a) b)))

Produces an atom by taking the last b blocks of size a from c.

a is a block size (see ++bloq).

b is an atom.

c is an atom.

~zod/try=> `@ub`12
0b1100
~zod/try=> `@ub`(end 0 3 12)
0b100
~zod/try=> (end 0 3 12)
4
~zod/try=> `@ub`(end 1 3 12)
0b1100
~zod/try=> (end 1 3 12)
12
~zod/try=> `@ux`'abc'
0x63.6261
~zod/try=> `@ux`(end 3 2 'abc')
0x6261
~zod/try=> `@t`(end 3 2 'abc')
'ab'

++fil

Fill bloqstream

++  fil                                                 ::  fill bloqstream
  |=  [a=bloq b=@ c=@]
  =+  n=0
  =+  d=c
  |-  ^-  @
  ?:  =(n b)
    (rsh a 1 d)
  $(d (add c (lsh a 1 d)), n +(n))

Produces an atom by repeating c for b blocks of size a.

a is a block size (see ++bloq).

b is an atom.

c is an atom.

~zod/try=> `@t`(fil 3 5 %a)
'aaaaa'
~zod/try=> `@t`(fil 5 10 %ceeb)
'ceebceebceebceebceebceebceebceebceebceeb'
~zod/try=> `@t`(fil 4 10 %eced)
'ʇʇʇʇʇʇʇʇʇʇed'
~zod/try=> `@tas`(fil 4 10 %bf)
%bfbfbfbfbfbfbfbfbfbf

++lsh

Left-shift

++  lsh                                                 ::  left-shift
  ~/  %lsh
  |=  [a=bloq b=@ c=@]
  (mul (bex (mul (bex a) b)) c)

Produces an atom by left-shifting c by b blocks of size a.

a is a block size (see ++bloq).

b is an atom.

c is an atom.

~zod/try=> `@ub`1
0b1
~zod/try=> `@ub`(lsh 0 1 1)
0b10
~zod/try=> (lsh 0 1 1)
2
~zod/try=> `@ub`255
0b1111.1111
~zod/try=> `@ub`(lsh 3 1 255)
0b1111.1111.0000.0000
~zod/try=> (lsh 3 1 255)
65.280

++met

Measure

++  met                                                 ::  measure
  ~/  %met
  |=  [a=bloq b=@]
  ^-  @
  =+  c=0
  |-
  ?:  =(0 b)  c
  $(b (rsh a 1 b), c +(c))

Computes the number of blocks of size a in b, producing an atom.

a is a block size (see ++bloq).

b is an atom.

~zod/try=> (met 0 1)
1
~zod/try=> (met 0 2)
2
~zod/try=> (met 3 255)
1
~zod/try=> (met 3 256)
2
~zod/try=> (met 3 'abcde')
5

++rap

Assemble non-zero

++  rap                                                 ::  assemble nonzero
  ~/  %rap
  |=  [a=bloq b=(list ,@)]
  ^-  @
  ?~  b  0
  (cat a i.b $(b t.b))

Concatenate a list of atoms b using blocksize a, producing an atom.

a is a block size (see ++bloq).

b is a list of atoms.

~zod/try=> `@ub`(rap 2 (limo [1 2 3 4 ~]))
0b100.0011.0010.0001
~zod/try=> `@ub`(rap 1 (limo [1 2 3 4 ~]))
0b1.0011.1001
~zod/try=> (rap 0 (limo [0 0 0 ~]))
0
~zod/try=> (rap 0 (limo [1 0 1 ~]))
3

++rep

Assemble single

++  rep                                                 ::  assemble single
  ~/  %rep
  |=  [a=bloq b=(list ,@)]
  ^-  @
  =+  c=0
  |-
  ?~  b  0
  (con (lsh a c (end a 1 i.b)) $(c +(c), b t.b))

Produces an atom by assembling a list of atoms b using block size a.

a is a block size (see ++bloq).

b is a list of atoms.

~zod/try=> `@ub`(rep 2 (limo [1 2 3 4 ~]))
0b100.0011.0010.0001
~zod/try=> (rep 0 (limo [0 0 1 ~]))
4
~zod/try=> (rep 0 (limo [0 0 0 1 ~]))
8
~zod/try=> (rep 0 (limo [0 1 0 0 ~]))
2
~zod/try=> (rep 0 (limo [0 1 0 1 ~]))
10
~zod/try=> (rep 0 (limo [0 1 0 1 0 1 ~]))
42
~zod/try=> `@ub`42
0b10.1010

++rip

Disassemble

++  rip                                                 ::  disassemble
  ~/  %rip
  |=  [a=bloq b=@]
  ^-  (list ,@)
  ?:  =(0 b)  ~
  [(end a 1 b) $(b (rsh a 1 b))]

Produces a list of atoms from the bits of b using block size a.

a is a block size (see ++bloq).

b is an atom.

~zod/try=> `@ub`155
0b1001.1011
~zod/try=> (rip 0 155)
~[1 1 0 1 1 0 0 1]
~zod/try=> (rip 2 155)
~[11 9]
~zod/try=> (rip 1 155)
~[3 2 1 2]
~zod/try=> `@ub`256
0b1.0000.0000
~zod/try=> (rip 0 256)
~[0 0 0 0 0 0 0 0 1]
~zod/try=> (rip 2 256)
~[0 0 1]
~zod/try=> (rip 3 256)
~[0 1]

++rsh

Right-shift

++  rsh                                                 ::  right-shift
  ~/  %rsh
  |=  [a=bloq b=@ c=@]
  (div c (bex (mul (bex a) b)))

Right-shifts c by b blocks of size a, producing an atom.

a is a block size (see ++bloq).

b is an atom.

c is an atom.

~zod/try=> `@ub`145
0b1001.0001
~zod/try=> `@ub`(rsh 1 1 145)
0b10.0100
~zod/try=> (rsh 1 1 145)
36
~zod/try=> `@ub`(rsh 2 1 145)
0b1001
~zod/try=> (rsh 2 1 145)
9
~zod/try=> `@ub`10
0b1010
~zod/try=> `@ub`(rsh 0 1 10)
0b101
~zod/try=> (rsh 0 1 10)
5
~zod/try=> `@ux`'abc'
0x63.6261
~zod/try=> `@t`(rsh 3 1 'abc')
'bc'
~zod/try=> `@ux`(rsh 3 1 'abc')
0x6362

++swap

Reverse block order

++  swap  |=([a=bloq b=@] (rep a (flop (rip a b))))     ::  reverse bloq order

Switches little ending to big and vice versa: produces an atom by reversing the block order of b using block size a.

a is a block size (see ++bloq).

b is an atom

~zod/try=> `@ub`24
0b1.1000
~zod/try=> (swap 0 24)
3
~zod/try=> `@ub`3
0b11
~zod/try=> (swap 0 0)
0
~zod/try=> (swap 0 128)
1

section 2cB, bit logic

++con

Binary OR

++  con                                                 ::  binary or
  ~/  %con
  |=  [a=@ b=@]
  =+  [c=0 d=0]
  |-  ^-  @
  ?:  ?&(=(0 a) =(0 b))  d
  %=  $
    a   (rsh 0 1 a)
    b   (rsh 0 1 b)
    c   +(c)
    d   %+  add  d  
          %^  lsh  0  c 
          ?&  =(0 (end 0 1 a)) 
              =(0 (end 0 1 b))
          ==
  ==

Computes the bit-wise logical OR of two atoms, a and b, producing an atom.

a is an atom

b is an atom

~zod/try=> (con 0b0 0b1)
1
~zod/try=> (con 0 1)
1
~zod/try=> (con 0 0)
0
~zod/try=> `@ub`(con 0b1111.0000 0b1.0011)
0b1111.0011    
~zod/try=> (con 4 4)
4
~zod/try=> (con 10.000 234)
10.234

++dis

Binary AND

++  dis                                                 ::  binary and
  ~/  %dis
  |=  [a=@ b=@]
  =|  [c=@ d=@]
  |-  ^-  @
  ?:  ?|(=(0 a) =(0 b))  d
  %=  $
    a   (rsh 0 1 a)
    b   (rsh 0 1 b)
    c   +(c)
    d   %+  add  d 
          %^  lsh  0  c 
          ?|  =(0 (end 0 1 a)) 
              =(0 (end 0 1 b))
          ==
  ==

Computes the bit-wise logical AND of two atoms a and b, producing an atom.

a is an atom

b is an atom

~zod/try=> `@ub`9
0b1001
~zod/try=> `@ub`5
0b101
~zod/try=> `@ub`(dis 9 5)
0b1
~zod/try=> (dis 9 5)
1
~zod/try=> `@ub`534
0b10.0001.0110
~zod/try=> `@ub`987
0b11.1101.1011
~zod/try=> `@ub`(dis 534 987)
0b10.0001.0010
~zod/try=> (dis 534 987)
530

++mix

Binary XOR

++  mix                                                 ::  binary xor
  ~/  %mix
  |=  [a=@ b=@]
  ^-  @
  =+  [c=0 d=0]
  |-
  ?:  ?&(=(0 a) =(0 b))  d
  %=  $
    a   (rsh 0 1 a)
    b   (rsh 0 1 b)
    c   +(c)
    d   (add d (lsh 0 c =((end 0 1 a) (end 0 1 b))))
  ==

Produces the bit-wise logical XOR of a and b, producing an atom.

a is an atom

b is an atom

~zod/try=> `@ub`2
0b10
~zod/try=> `@ub`3
0b11
~zod/try=> `@ub`(mix 2 3)
0b1
~zod/try=> (mix 2 3)
1
~zod/try=> `@ub`(mix 2 2)
0b0
~zod/try=> (mix 2 2)
0

++not

Binary NOT

++  not  |=  [a=bloq b=@ c=@]                           ::  binary not (sized)
  (mix c (dec (bex (mul b (bex a)))))

Computes the bit-wise logical NOT of the bottom b blocks of size a of c.

a is a block size (see ++bloq).

b is an atom.

c is an atom.

~zod/try=> `@ub`24
0b1.1000
~zod/try=> (not 0 5 24)
7
~zod/try=> `@ub`7
0b111
~zod/try=> (not 2 5 24)
1.048.551
~zod/try=> (not 2 5 1.048.551)
24
~zod/try=> (not 1 1 (not 1 1 10))
10

section 2cC, noun orders

++aor

Alphabetic order

++  aor                                                 ::  alphabetic-order
  ~/  %aor
  |=  [a=* b=*]
  ^-  ?
  ?:  =(a b)  &
  ?.  ?=(@ a)
    ?:  ?=(@ b)  |
    ?:  =(-.a -.b)
      $(a +.a, b +.b)
    $(a -.a, b -.b)
  ?.  ?=(@ b)  &
  |-
  =+  [c=(end 3 1 a) d=(end 3 1 b)]
  ?:  =(c d)
    $(a (rsh 3 1 a), b (rsh 3 1 b))
  (lth c d)

Computes whether a and b are in alphabetical order, producing a loobean.

a is a noun.

b is a noun.

~zod/try=> (aor 'a' 'b')
%.y
~zod/try=> (aor 'b' 'a')
%.n
~zod/try=> (aor "foo" "bar")
%.n
~zod/try=> (aor "bar" "foo")
%.y
~zod/try=> (aor "abcdefz" "abcdefa")
%.n
~zod/try=> (aor "abcdefa" "abcdefz")
%.y
~zod/try=> (aor 10.000 17.000)
%.y
~zod/try=> (aor 10 9)
%.n

++dor

Numeric order

++  dor                                                 ::  d-order
  ~/  %dor
  |=  [a=* b=*]
  ^-  ?
  ?:  =(a b)  &
  ?.  ?=(@ a)
    ?:  ?=(@ b)  |
    ?:  =(-.a -.b)
      $(a +.a, b +.b)
    $(a -.a, b -.b)
  ?.  ?=(@ b)  &
  (lth a b)

Computes whether a and b are in ascending numeric order, producing a loobean.

a is a noun.

b is a noun.

~zod/try=> (dor 1 2)
%.y
~zod/try=> (dor 2 1)
%.n
~zod/try=> (dor ~[1 2 3] ~[1 2 4])
%.y
~zod/try=> (dor ~[1 2 4] ~[1 2 3])
%.n
~zod/try=> (dor (limo ~[99 100 10.000]) ~[99 101 10.000])
%.y
~zod/try=> (dor ~[99 101 10.999] (limo ~[99 100 10.000]))
%.n

++gor

Hash order

++  gor                                                 ::  g-order
  ~/  %gor
  |=  [a=* b=*]
  ^-  ?
  =+  [c=(mug a) d=(mug b)]
  ?:  =(c d)
    (dor a b)
  (lth c d)

XX revisit

~zod/try=> (gor 'd' 'c')
%.y
~zod/try=> 'd'
'd'
~zod/try=> 'c'
~zod/try=> `@ud`'d'
100
~zod/try=> `@ud`'c'
99
~zod/try=> (mug 'd')
1.628.185.714
~zod/try=> (mug 'c')
1.712.073.811
~zod/try=> (gor 'd' 'c')
%.y
~zod/try=> (gor 'c' 'd')
%.n
~zod/try=> (gor "foo" "bar")
%.n
~zod/try=> (gor (some 10) (limo [1 2 3 ~]))
%.n

++hor

Hash order

++  hor                                                 ::  h-order
  ~/  %hor
  |=  [a=* b=*]
  ^-  ?
  ?:  ?=(@ a)
    ?.  ?=(@ b)  &
    (gor a b)
  ?:  ?=(@ b)  |
  ?:  =(-.a -.b)
    (gor +.a +.b)
  (gor -.a -.b)

XX revisit

Recursive hash comparator gate.

~zod/try=> (hor . 1)
%.n
~zod/try=> (hor 1 2)
%.y
~zod/try=> (hor "abc" "cba")
%.y
~zod/try=> (hor 'c' 'd')
%.n

++vor

++  vor                                                 ::  v-order
  ~/  %vor
  |=  [a=* b=*]
  ^-  ?
  =+  [c=(mug (mug a)) d=(mug (mug b))]
  ?:  =(c d)
    (dor a b)
  (lth c d)

XX revisit

Double hash comparator gate.

~zod/try=> (vor 'f' 'g')
%.y
~zod/try=> (vor 'a' 'z')
%.n
~zod/try=> (vor 43.326 41.106)
%.n

section 2cD, insecure hashing

++fnv

++  fnv  |=(a=@ (end 5 1 (mul 16.777.619 a)))           ::  FNV scrambler

Hashes an atom with the 32-bit FNV non-cryptographic hash algorithm. Multiplies a by the prime number 16,777,619 and then takes the block of size 5 off the product's end, producing atom.

a is an atom.

~zod/try=> (fnv 10.000)
272.465.456
~zod/try=> (fnv 10.001)
289.243.075
~zod/try=> (fnv 1)
16.777.619

++mum

++  mum                                                 ::  mug with murmur3
  ~/  %mum
  |=  a=*
  |^  (trim ?@(a a (mix $(a -.a) (mix 0x7fff.ffff $(a +.a)))))
  ++  spec                                              ::  standard murmur3
    |=  [syd=@ key=@]
    ?>  (lte (met 5 syd) 1)
    =+  ^=  row
        |=  [a=@ b=@] 
        (con (end 5 1 (lsh 0 a b)) (rsh 0 (sub 32 a) b))
    =+  mow=|=([a=@ b=@] (end 5 1 (mul a b)))
    =+  len=(met 5 key)
    =-  =.  goc  (mix goc len)
        =.  goc  (mix goc (rsh 4 1 goc))
        =.  goc  (mow goc 0x85eb.ca6b)
        =.  goc  (mix goc (rsh 0 13 goc))
        =.  goc  (mow goc 0xc2b2.ae35)
        (mix goc (rsh 4 1 goc))
    ^=  goc
    =+  [inx=0 goc=syd]
    |-  ^-  @
    ?:  =(inx len)  goc
    =+  kop=(cut 5 [inx 1] key)
    =.  kop  (mow kop 0xcc9e.2d51)
    =.  kop  (row 15 kop) 
    =.  kop  (mow kop 0x1b87.3593)
    =.  goc  (mix kop goc)
    =.  goc  (row 13 goc)
    =.  goc  (end 5 1 (add 0xe654.6b64 (mul 5 goc)))
    $(inx +(inx))
  ::
  ++  trim                                              ::  31-bit nonzero
    |=  key=@
    =+  syd=0xcafe.babe
    |-  ^-  @
    =+  haz=(spec syd key)
    =+  ham=(mix (rsh 0 31 haz) (end 0 31 haz))
    ?.(=(0 ham) ham $(syd +(syd)))
  --
::

XX document

~zod/try=> (mum 10.000)
1.232.632.901
~zod/try=> (mum 10.001)
658.093.079
~zod/try=> (mum 1)
818.387.364
~zod/try=> (mum (some 10))
1.177.215.703
~zod/try=> (mum ~[1 2 3 4 5])
1.517.902.092

++mug

++  mug                                                 ::  31bit nonzero FNV1a
  ~/  %mug
  |=  a=*
  ?^  a
    =+  b=[p=$(a -.a) q=$(a +.a)]
    |-  ^-  @
    =+  c=(fnv (mix p.b (fnv q.b)))
    =+  d=(mix (rsh 0 31 c) (end 0 31 c))
    ?.  =(0 c)  c
    $(q.b +(q.b))
  =+  b=2.166.136.261
  |-  ^-  @
  =+  c=b
  =+  [d=0 e=(met 3 a)]
  |-  ^-  @
  ?:  =(d e)
    =+  f=(mix (rsh 0 31 c) (end 0 31 c))
    ?.  =(0 f)  f
    ^$(b +(b))
  $(c (fnv (mix c (cut 3 [d 1] a))), d +(d))

Hashes a with the 31-bit nonzero FNV-1a non-cryptographic hash algorithm, producing an atom.

~zod/try=> (mug 10.000)
178.152.889
~zod/try=> (mug 10.001)
714.838.017
~zod/try=> (mug 1)
67.918.732
~zod/try=> (mug (some 10))
1.872.403.737
~zod/try=> (mug (limo [1 2 3 4 5 ~]))
1.067.931.605

section 2cE, phonetic base

++po

++  po
  ~/  %po
  =+  :-  ^=  sis                                       ::  prefix syllables
      'dozmarbinwansamlitsighidfidlissogdirwacsabwissib\
      /rigsoldopmodfoglidhopdardorlorhodfolrintogsilmir\
      /holpaslacrovlivdalsatlibtabhanticpidtorbolfosdot\
      /losdilforpilramtirwintadbicdifrocwidbisdasmidlop\
      /rilnardapmolsanlocnovsitnidtipsicropwitnatpanmin\
      /ritpodmottamtolsavposnapnopsomfinfonbanporworsip\
      /ronnorbotwicsocwatdolmagpicdavbidbaltimtasmallig\
      /sivtagpadsaldivdactansidfabtarmonranniswolmispal\
      /lasdismaprabtobrollatlonnodnavfignomnibpagsopral\
      /bilhaddocridmocpacravripfaltodtiltinhapmicfanpat\
      /taclabmogsimsonpinlomrictapfirhasbosbatpochactid\
      /havsaplindibhosdabbitbarracparloddosbortochilmac\
      /tomdigfilfasmithobharmighinradmashalraglagfadtop\
      /mophabnilnosmilfopfamdatnoldinhatnacrisfotribhoc\
      /nimlarfitwalrapsarnalmoslandondanladdovrivbacpol\
      /laptalpitnambonrostonfodponsovnocsorlavmatmipfap'
      ^=  dex                                           ::  suffix syllables
      'zodnecbudwessevpersutletfulpensytdurwepserwylsun\
      /rypsyxdyrnuphebpeglupdepdysputlughecryttyvsydnex\
      /lunmeplutseppesdelsulpedtemledtulmetwenbynhexfeb\
      /pyldulhetmevruttylwydtepbesdexsefwycburderneppur\
      /rysrebdennutsubpetrulsynregtydsupsemwynrecmegnet\
      /secmulnymtevwebsummutnyxrextebfushepbenmuswyxsym\
      /selrucdecwexsyrwetdylmynmesdetbetbeltuxtugmyrpel\
      /syptermebsetdutdegtexsurfeltudnuxruxrenwytnubmed\
      /lytdusnebrumtynseglyxpunresredfunrevrefmectedrus\
      /bexlebduxrynnumpyxrygryxfeptyrtustyclegnemfermer\
      /tenlusnussyltecmexpubrymtucfyllepdebbermughuttun\
      /bylsudpemdevlurdefbusbeprunmelpexdytbyttyplevmyl\
      /wedducfurfexnulluclennerlexrupnedlecrydlydfenwel\
      /nydhusrelrudneshesfetdesretdunlernyrsebhulryllud\
      /remlysfynwerrycsugnysnyllyndyndemluxfedsedbecmun\
      /lyrtesmudnytbyrsenwegfyrmurtelreptegpecnelnevfes'
  |%

Provides the phonetic syllables and name generators for the Urbit naming system. The two faces, sis and dex are available to the arms contained in this section.


++ind

Parse prefix

  ++  ind  ~/  %ind                                     ::  parse prefix
           |=  a=@
           =+  b=0
           |-  ^-  (unit ,@)
           ?:(=(256 b) ~ ?:(=(a (tod b)) [~ b] $(b +(b))))

Produces the byte of the right-hand syllable a.

a is an atom.

~zod/try=> (ind:po 'zod')
[~ 0]
~zod/try=> (ind:po 'zam')
~
~zod/try=> (ind:po 'del')
[~ 37]

++ins

Parse suffix

  ++  ins  ~/  %ins                                     ::  parse suffix
           |=  a=@
           =+  b=0
           |-  ^-  (unit ,@)
           ?:(=(256 b) ~ ?:(=(a (tos b)) [~ b] $(b +(b))))

Produces the byte of the left-hand phonetic syllable b.

a is an atom.

~zod/try=> (ins:po 'mar')
[~ 1]
~zod/try=> (ins:po 'son')
[~ 164]
~zod/try=> (ins:po 'pit')
[~ 242]
~zod/try=> (ins:po 'pok')
~

++tod

Fetch prefix

  ++  tod  ~/  %tod                                     ::  fetch prefix
           |=(a=@ ?>((lth a 256) (cut 3 [(mul 3 a) 3] dex)))

Produces the phonetic prefix syllable from index a within dex as an atom.

a is an atom

~zod/try=> `@t`(tod:po 1)
'nec'
~zod/try=> `@t`(tod:po 98)
'dec'
~zod/try=> `@t`(tod:po 0)
'zod'
~zod/try=> `@t`(tod:po 150)
'ryg'
~zod/try=> `@t`(tod:po 255)
'fes'
~zod/try=> `@t`(tod:po 256)
! exit

++tos

Fetch suffix

  ++  tos  ~/  %tos                                     ::  fetch suffix
           |=(a=@ ?>((lth a 256) (cut 3 [(mul 3 a) 3] sis)))

Produces the phonetic prefix syllable from index a within sis as an atom.

~zod/try=> `@t`(tos:po 0)
'doz'
~zod/try=> `@t`(tos:po 120)
'fab'
~zod/try=> `@t`(tos:po 43)
'pid'
~zod/try=> `@t`(tos:po 253)
'mat'

section 2cF, signed and modular ints

++si

++  si  !:                                              ::  signed integer
  |%

Container for the signed integer functions.


++abs

++  abs  |=(a=@s (add (end 0 1 a) (rsh 0 1 a)))       ::  absolute value

Produces the absolute value of a signed integer.

a is a signed integer, @s.

~zod/try=> (abs:si -2)
2
~zod/try=> (abs:si -10.000)
10.000
~zod/try=> (abs:si --2)
2

++dif

  ++  dif  |=  [a=@s b=@s]                              ::  subtraction
           (sum a (new !(syn b) (abs b)))

Produces the difference between two signed integers b and c.

a is a signed integer, @s.

b is a signed integer, @s.

~zod/try=> (dif:si --10 -7)
--17
~zod/try=> (dif:si --10 --7)
--3
~zod/try=> (dif:si `@s`0 --7)
-7
~zod/try=> (dif:si `@s`0 `@s`7)
--4

++dul

  ++  dul  |=  [a=@s b=@]                               ::  modulus
           =+(c=(old a) ?:(-.c (mod +.c b) (sub b +.c)))

Produces the modulus of two signed integers.

a is a signed integer, @s.

b is an atom.

~zod/try=> (dul:si --9 3)
0
~zod/try=> (dul:si --9 4)
1
~zod/try=> (dul:si --9 5)
4
~zod/try=> (dul:si --9 6)
3
~zod/try=> (dul:si --90 --10)
10

++fra

  ++  fra  |=  [a=@s b=@s]                              ::  divide
           (new =(0 (mix (syn a) (syn b))) (div (abs a) (abs b)))

Produces the quotient of two signed integers.

a is a signed integer, @s.

b is a signed integer, @s.

~zod/try=> (fra:si --10 -2)
-5
~zod/try=> (fra:si -20 -5)
--4

++new

  ++  new  |=  [a=? b=@]                                ::  [sign value] to @s
           `@s`?:(a (mul 2 b) ?:(=(0 b) 0 +((mul 2 (dec b)))))

Produces a signed integer from a loobean sign value a and an atom b.

a is a loobean.

b is an atom.

~zod/try=> (new:si [& 10])
--10
~zod/try=> (new:si [| 10])
-10
~zod/try=> (new:si [%.y 7])
--7

++old

  ++  old  |=(a=@s [(syn a) (abs a)])                   ::  [sign value]

Produces the cell [sign value] representations of a signed integer.

a is a signed integer, @s.

~zod/try=> (old:si 7)
! type-fail
! exit
~zod/try=> (old:si -7)
[%.n 7]
~zod/try=> (old:si --7)
[%.y 7]
~zod/try=> (old:si `@s`7)
[%.n 4]
~zod/try=> (old:si -0)
[%.y 0]

++pro

  ++  pro  |=  [a=@s b=@s]                              ::  multiplication
           (new =(0 (mix (syn a) (syn b))) (mul (abs a) (abs b)))

Produces the product of two signed integers.

a is a signed integer, @s.

b is a signed integer, @s.

~zod/try=> (pro:si -4 --2)
-8
~zod/try=> (pro:si -4 -2)
--8
~zod/try=> (pro:si --10.000.000 -10)
-100.000.000
~zod/try=> (pro:si -1.337 --0)
--0

++rem

  ++  rem  |=([a=@s b=@s] (dif a (pro b (fra a b))))    ::  remainder

Produces the remainder from a division of two signed integers.

a is a signed integer, @s.

b is a signed integer, @s.

~zod/try=> (rem:si -10 -4)
-2
~zod/try=> (rem:si --10 --4)
--2
~zod/try=> (rem:si --10 -4)
--2
~zod/try=> (rem:si --7 --3)
--1
~zod/try=> (rem:si --0 --10.000)
--0

++sum

  ++  sum  |=  [a=@s b=@s]                              ::  addition
           ~|  %si-sum
           =+  [c=(old a) d=(old b)]
           ?:  -.c
             ?:  -.d
               (new & (add +.c +.d))
             ?:  (gte +.c +.d)
               (new & (sub +.c +.d))
             (new | (sub +.d +.c))
           ?:  -.d
             ?:  (gte +.c +.d)
               (new | (sub +.c +.d))
             (new & (sub +.d +.c))
           (new | (add +.c +.d))

Sum two signed integers.

b is a signed integer, @s.

c is a signed integer, @s.

~zod/try=> (sum:si --10 --10)
--20
~zod/try=> (sum:si --10 -0)
--10
~zod/try=> (sum:si -10 -7)
-17
~zod/try=> (sum:si -10 --7)
-3

++sun

  ++  sun  |=(a=@u (mul 2 a))                           ::  @u to @s

Produces a signed integer from an unsigned integer.

Note that the result must be manually cast to some @s odor to be inferred as an unsigned integer in the type system.

a is an unsigned integer, @u.

~zod/try=> `@s`10
--5
~zod/try=> (sun:si 10)
20
~zod/try=> `@s`(sun:si 10)
--10
~zod/try=> `@sd`(sun:si 10)
--10
~zod/try=> `@sd`(sun:si 12.345)
--12.345

++syn

  ++  syn  |=(a=@s =(0 (end 0 1 a)))                    ::  sign test

Produce the sign of a signed integer, & being posiitve, | negative.

a is a signed integer, @s.

~zod/try=> (syn:si -2)
%.n
~zod/try=> (syn:si --2)
%.y
~zod/try=> (syn:si -0)
%.y

++cmp

  ++  cmp  |=  [a=@s b=@s]                              ::  compare
           ^-  @s
           ?:  =(a b)
             --0
           ?:  (syn a)
             ?:  (syn b)
               ?:  (gth a b)
                 --1
               -1
             --1
          ?:  (syn b)
            -1
          ?:  (gth a b)
            -1
          --1

Compare two signed integers.

b is a signed integer, @s.

c is a signed integer, @s.

~zod/try=> (cmp:si --10 --10)
--0
~zod/try=> (cmp:si --10 -0)
--1
~zod/try=> (cmp:si -10 -7)
-1
~zod/try=> (cmp:si -10 --7)
-1

++dif

  ++  dif  |=([b=@ c=@] (sit (sub (add out (sit b)) (sit c))))

Produces the difference between two atoms in the modular basis representation.

b is an atom.

c is an atom.

~zod/try=> (~(dif fe 3) 63 64)
255
~zod/try=> (~(dif fe 3) 5 10)
251
~zod/try=> (~(dif fe 3) 0 1)
255
~zod/try=> (~(dif fe 0) 9 10)
1
~zod/try=> (~(dif fe 0) 9 11)
0
~zod/try=> (~(dif fe 0) 9 12)
1
~zod/try=> (~(dif fe 2) 9 12)
13
~zod/try=> (~(dif fe 2) 63 64)
15

++inv

  ++  inv  |=(b=@ (sub (dec out) (sit b)))

Inverts the order of the modular field.

b is an atom.

~zod/try=> (~(inv fe 3) 255)
0
~zod/try=> (~(inv fe 3) 256)
255
~zod/try=> (~(inv fe 3) 0)
255
~zod/try=> (~(inv fe 3) 1)
254
~zod/try=> (~(inv fe 3) 2)
253
~zod/try=> (~(inv fe 3) 55)
200

++net

  ++  net  |=  b=@  ^-  @
           =>  .(b (sit b))
           ?:  (lte a 3)
             b
           =+  c=(dec a)
           %+  con
             (lsh c 1 $(a c, b (cut c [0 1] b)))
           $(a c, b (cut c [1 1] b))

Reverse bytes within block.

b is an atom.

~zod/try=> (~(net fe 3) 64)
64
~zod/try=> (~(net fe 3) 128)
128
~zod/try=> (~(net fe 3) 255)
255
~zod/try=> (~(net fe 3) 256)
0
~zod/try=> (~(net fe 3) 257)
1
~zod/try=> (~(net fe 3) 500)
244
~zod/try=> (~(net fe 3) 511)
255
~zod/try=> (~(net fe 3) 512)
0
~zod/try=> (~(net fe 3) 513)
1
~zod/try=> (~(net fe 3) 0)
0
~zod/try=> (~(net fe 3) 1)
1
~zod/try=> (~(net fe 0) 1)
1
~zod/try=> (~(net fe 0) 2)
0
~zod/try=> (~(net fe 0) 3)
1
~zod/try=> (~(net fe 6) 1)
72.057.594.037.927.936
~zod/try=> (~(net fe 6) 2)
144.115.188.075.855.872
~zod/try=> (~(net fe 6) 3)
216.172.782.113.783.808
~zod/try=> (~(net fe 6) 4)
288.230.376.151.711.744
~zod/try=> (~(net fe 6) 5)
360.287.970.189.639.680
~zod/try=> (~(net fe 6) 6)
432.345.564.227.567.616
~zod/try=> (~(net fe 6) 7)
504.403.158.265.495.552
~zod/try=> (~(net fe 6) 512)
562.949.953.421.312
~zod/try=> (~(net fe 6) 513)
72.620.543.991.349.248

++out

  ++  out  (bex (bex a))

The maximum integer value that the current block can store.

~zod/try=> ~(out fe 0)
2
~zod/try=> ~(out fe 1)
4
~zod/try=> ~(out fe 2)
16
~zod/try=> ~(out fe 3)
256
~zod/try=> ~(out fe 4)
65.536
~zod/try=> ~(out fe 10)
\/179.769.313.486.231.590.772.930.519.078.902.473.361.797.697.894.230.657.\/
  273.430.081.157.732.675.805.500.963.132.708.477.322.407.536.021.120.113.
  879.871.393.357.658.789.768.814.416.622.492.847.430.639.474.124.377.767.
  893.424.865.485.276.302.219.601.246.094.119.453.082.952.085.005.768.838.
  150.682.342.462.881.473.913.110.540.827.237.163.350.510.684.586.298.239.
  947.245.938.479.716.304.835.356.329.624.224.137.216
\/                                                                        \/

++rol

  ++  rol  |=  [b=bloq c=@ d=@]  ^-  @                  ::  roll left
           =+  e=(sit d)
           =+  f=(bex (sub a b))
           =+  g=(mod c f)
           (sit (con (lsh b g e) (rsh b (sub f g) e)))

Roll d to the left by c b-sized blocks.

b is a block size (see ++bloq).

c is an atom.

d is an atom.

~zod/try=> `@ux`(~(rol fe 6) 4 3 0xabac.dedf.1213)
0x1213.0000.abac.dedf
~zod/try=> `@ux`(~(rol fe 6) 4 2 0xabac.dedf.1213)
0xdedf.1213.0000.abac
~zod/try=> `@t`(~(rol fe 5) 3 1 'dfgh')
'hdfg'
~zod/try=> `@t`(~(rol fe 5) 3 2 'dfgh')
'ghdf'
~zod/try=> `@t`(~(rol fe 5) 3 0 'dfgh')
'dfgh'

++ror

  ++  ror  |=  [b=bloq c=@ d=@]  ^-  @                  ::  roll right
           =+  e=(sit d)
           =+  f=(bex (sub a b))
           =+  g=(mod c f)
           (sit (con (rsh b g e) (lsh b (sub f g) e)))

Roll d to the right by c b-sized blocks.

b is a block size (see ++bloq).

c is an atom.

d is an atom.

~zod/try=> `@ux`(~(ror fe 6) 4 1 0xabac.dedf.1213)
0x1213.0000.abac.dedf
~zod/try=> `@ux`(~(ror fe 6) 3 5 0xabac.dedf.1213)
0xacde.df12.1300.00ab
~zod/try=> `@ux`(~(ror fe 6) 3 3 0xabac.dedf.1213)
0xdf12.1300.00ab.acde
~zod/try=> `@t`(~(rol fe 5) 3 0 'hijk')
'hijk'
~zod/try=> `@t`(~(rol fe 5) 3 1 'hijk')
'khij'
~zod/try=> `@t`(~(rol fe 5) 3 2 'hijk')
'jkhi'

++sum

  ++  sum  |=([b=@ c=@] (sit (add b c)))                ::  wrapping add

Sum two numbers in this modular field.

b is an atom.

c is an atom.

~zod/try=> (~(sum fe 3) 10 250)
4
~zod/try=> (~(sum fe 0) 0 1)
1
~zod/try=> (~(sum fe 0) 0 2)
0
~zod/try=> (~(sum fe 2) 14 2)
0
~zod/try=> (~(sum fe 2) 14 3)
1
~zod/try=> (~(sum fe 4) 10.000 256)
10.256
~zod/try=> (~(sum fe 4) 10.000 100.000)
44.464

++sit

  ++  sit  |=(b=@ (end a 1 b))                          ::  enforce modulo

Produce an atom in the current modular block representation.

b is an atom.

~zod/try=> (~(sit fe 3) 255)
255
~zod/try=> (~(sit fe 3) 256)
0
~zod/try=> (~(sit fe 3) 257)
1
~zod/try=> (~(sit fe 2) 257)
1
~zod/try=> (~(sit fe 2) 10.000)
0
~zod/try=> (~(sit fe 2) 100)
4
~zod/try=> (~(sit fe 2) 19)
3
~zod/try=> (~(sit fe 2) 17)
1
~zod/try=> (~(sit fe 0) 17)
1
~zod/try=> (~(sit fe 0) 0)
0
~zod/try=> (~(sit fe 0) 1)
1

section 2cG, floating point

XX awaiting interface rewrite

section 2cH, urbit time

Note that entering '-<-' in the shell produces the current time in @da format. We use this for many of our examples.

~zod/try=> -<-
~2014.8.4..19.39.59..9288

++year

++  year                                                ::  date to @d
  |=  det=date
  ^-  @d
  =+  ^=  yer
      ?:  a.det
        (add 292.277.024.400 y.det)
      (sub 292.277.024.400 (dec y.det))
  =+  day=(yawn yer m.det d.t.det)
  (yule day h.t.det m.t.det s.t.det f.t.det)

Accept a parsed date of form [[a=? y=@ud] m=@ud t=tarp] and produce its @drepresentation.

det is a ++date

~zod/try=> (year [[a=%.y y=2.014] m=8 t=[d=4 h=20 m=4 s=57 f=~[0xd940]]])
0x8000000d227df4e9d940000000000000

++yore

++  yore                                                ::  @d to date
  |=  now=@d
  ^-  date
  =+  rip=(yell now)
  =+  ger=(yall d.rip)
  :-  ?:  (gth y.ger 292.277.024.400)
        [a=& y=(sub y.ger 292.277.024.400)]
      [a=| y=+((sub 292.277.024.400 y.ger))]
  [m.ger d.ger h.rip m.rip s.rip f.rip]

Produces a ++date from a @d

now is a @d.

~zod/try=> (yore -<-)
[[a=%.y y=2.014] m=8 t=[d=4 h=20 m=17 s=1 f=~[0x700d]]]
~zod/try=> (yore -<-)
[[a=%.y y=2.014] m=8 t=[d=4 h=20 m=28 s=53 f=~[0x7b82]]]

++yell

++  yell                                                ::  tarp from @d
  |=  now=@d
  ^-  tarp
  =+  sec=(rsh 6 1 now)
  =+  ^=  fan
      =+  [muc=4 raw=(end 6 1 now)]
      |-  ^-  (list ,@ux)
      ?:  |(=(0 raw) =(0 muc))
        ~
      =>  .(muc (dec muc))
      [(cut 4 [muc 1] raw) $(raw (end 4 muc raw))]
  =+  day=(div sec day:yo)
  =>  .(sec (mod sec day:yo))
  =+  hor=(div sec hor:yo)
  =>  .(sec (mod sec hor:yo))
  =+  mit=(div sec mit:yo)
  =>  .(sec (mod sec mit:yo))
  [day hor mit sec fan]

Produce a parsed daily time format from an atomic date.

now is a @d.

~zod/try=> (yell ~2014.3.20..05.42.53..7456)
[d=106.751.991.820.094 h=5 m=42 s=53 f=~[0x7456]]
~zod/try=> (yell ~2014.6.9..19.09.40..8b66)
[d=106.751.991.820.175 h=19 m=9 s=40 f=~[0x8b66]]
~zod/try=> (yell ~1776.7.4)
[d=106.751.991.733.273 h=0 m=0 s=0 f=~]

++yule

++  yule                                                ::  time atom
  |=  rip=tarp
  ^-  @d
  =+  ^=  sec  ;:  add
                 (mul d.rip day:yo)
                 (mul h.rip hor:yo)
                 (mul m.rip mit:yo)
                 s.rip
               ==
  =+  ^=  fac  =+  muc=4
               |-  ^-  @
               ?~  f.rip
                 0
               =>  .(muc (dec muc))
               (add (lsh 4 muc i.f.rip) $(f.rip t.f.rip))
  (con (lsh 6 1 sec) fac)

Accept a ++tarp, a parsed daily time, and produces a time atom, @d.

rip is a ++tarp.

~zod/try=> =murica (yell ~1776.7.4)
~zod/try=> murica
[d=106.751.991.733.273 h=0 m=0 s=0 f=~]
~zod/try=> (yule murica)
0x8000000b62aaf5800000000000000000
~zod/try=> `@da`(yule murica)
~1776.7.4
~zod/try=> `@da`(yule (yell ~2014.3.20..05.42.53..7456))
~2014.3.20..05.42.53..7456
~zod/try=> `tarp`[31 12 30 0 ~]
[d=31 h=12 m=30 s=0 f=~]
~zod/try=> `@dr`(yule `tarp`[31 12 30 0 ~])
~d31.h12.m30

++yall

++  yall                                                ::  day # to day of year
  |=  day=@ud
  ^-  [y=@ud m=@ud d=@ud]
  =+  [era=0 cet=0 lep=_?]
  =>  .(era (div day era:yo), day (mod day era:yo))
  =>  ^+  .
      ?:  (lth day +(cet:yo))
        .(lep &, cet 0)
      =>  .(lep |, cet 1, day (sub day +(cet:yo)))
      .(cet (add cet (div day cet:yo)), day (mod day cet:yo))
  =+  yer=(add (mul 400 era) (mul 100 cet))
  |-  ^-  [y=@ud m=@ud d=@ud]
  =+  dis=?:(lep 366 365)
  ?.  (lth day dis)
    =+  ner=+(yer)
    $(yer ner, day (sub day dis), lep =(0 (end 0 2 ner)))
  |-  ^-  [y=@ud m=@ud d=@ud]
  =+  [mot=0 cah=?:(lep moy:yo moh:yo)]
  |-  ^-  [y=@ud m=@ud d=@ud]
  =+  zis=(snag mot cah)
  ?:  (lth day zis)
    [yer +(mot) +(day)]
  $(mot +(mot), day (sub day zis))

Produce the date tuple of [y=@ud m=@ud d=@ud] of the year, month, and day from a number of days from the beginning of time.

day is an unsigned decimal, @ud.

~zod/try=> (yall 198)
[y=0 m=7 d=17]
~zod/try=> (yall 90.398)
[y=247 m=7 d=3]
~zod/try=> (yall 0)
[y=0 m=1 d=1]

++yawn

++  yawn                                                ::  days since Jesus
  |=  [yer=@ud mot=@ud day=@ud]
  ^-  @ud
  =>  .(mot (dec mot), day (dec day))
  =>  ^+  .
      %=    .
          day
        =+  cah=?:((yelp yer) moy:yo moh:yo)
        |-  ^-  @ud
        ?:  =(0 mot)
          day
        $(mot (dec mot), cah (slag 1 cah), day (add day (snag 0 cah)))
      ==
  |-  ^-  @ud
  ?.  =(0 (mod yer 4))
    =+  ney=(dec yer)
    $(yer ney, day (add day ?:((yelp ney) 366 365)))
  ?.  =(0 (mod yer 100))
    =+  nef=(sub yer 4)
    $(yer nef, day (add day ?:((yelp nef) 1.461 1.460)))
  ?.  =(0 (mod yer 400))
    =+  nec=(sub yer 100)
    $(yer nec, day (add day ?:((yelp nec) 36.525 36.524)))
  (add day (mul (div yer 400) (add 1 (mul 4 36.524))))

Inverse of yall, computes number of days A.D. from y/m/d date as the tuple [yer=@ud mot=@ud day=@ud].

yer is an unsigned decimal, @ud.

mon is an unsigned decimal, @ud.

day is an unsigned decimal, @ud.

~zod/try=> (yawn 2.014 8 4)
735.814
~zod/try=> (yawn 1.776 7 4)
648.856
~zod/try=> (yawn 1.990 10 11)
727.116

++yelp

++  yelp                                                ::  leap year
  |=  yer=@ud  ^-  ?
  &(=(0 (mod yer 4)) |(!=(0 (mod yer 100)) =(0 (mod yer 400))))

Determines whether a year contains an ISO 8601 leap week. Produces a loobean.

yer is an unsigned decimal, @ud.

~zod/try=> (yelp 2.014)
%.n
~zod/try=> (yelp 2.008)
%.y
~zod/try=> (yelp 0)
%.y
~zod/try=> (yelp 14.011)
%.n

++yo

++  yo                                                  ::  time constants

Useful constants for interacting with earth time.

++cet

  |%  ++  cet  36.524                 ::  (add 24 (mul 100 365))

Days in a century. Derived by multiplying the number of days in a year (365) by the number of years in a century (100), then adding the number days from leap years in a century (24).

~zod/try=> cet:yo
36.524
~zod/try=> (add 365 cet:yo)
36.889
~zod/try=> (sub (add 24 (mul 100 365)) cet:yo)
0

++day

      ++  day  86.400                 ::  (mul 24 hor)

Number of seconds in a day.

~zod/try=> day:yo
86.400
~zod/try=> (add 60 day:yo)
86.460

++era

      ++  era  146.097                ::  (add 1 (mul 4 cet))

XX Revisit


++hor

      ++  hor  3.600                  ::  (mul 60 mit)

The number of seconds in an hour. Derived by multiplying the number of seconds in a minute by the minutes in an hour.

~zod/try=> hor:yo
3.600
~zod/try=> (div hor:yo 60)
60

++jes

      ++  jes  106.751.991.084.417    ::  (mul 730.692.561 era)

XX Revisit

~zod/try=> jes:yo
106.751.991.084.417

++mit

      ++  mit  60

The number of seconds in a minute.

~zod/try=> mit:yo
60

++moh

      ++  moh  `(list ,@ud)`[31 28 31 30 31 30 31 31 30 31 30 31 ~]

The days in each month of the Gregorian common year. A list of unsigned decimal atoms (Either 28, 30, or 31) denoting the number of days in the month at the year at that index.

~zod/try=> moh:yo
~[31 28 31 30 31 30 31 31 30 31 30 31]
~zod/try=> (snag 4 moh:yo)
31

++moy

      ++  moy  `(list ,@ud)`[31 29 31 30 31 30 31 31 30 31 30 31 ~]

The days in each month of the Gregorian leap-year. A list of unsigned decimal atoms (Either 29,30, or 31) denoting the number of days in the month at the leap-year at that index.

~zod/try=> moy:yo
~[31 29 31 30 31 30 31 31 30 31 30 31]
~zod/try=> (snag 1 moy:yo)
29

++qad

      ++  qad  126.144.001            ::  (add 1 (mul 4 yer))

The number of seconds in four years. Derived by adding one second to the number of seconds in four years.

~zod/try=> qad:yo
126.144.001

++yer

      ++  yer  31.536.000             ::  (mul 365 day)

The number of seconds in a year. Derived by multiplying the number of seconds in a day by 365.

~zod/try=> yer:yo
31.536.000

section 2cI, almost macros

++cury

++  cury
  |*  [a=_|=(^ _*) b=*]
  |*  c=_+<+.a
  (a b c)

Curry a gate, binding the head of its sample

a is a gate.

b is a noun.

~zod/try=> =mol (cury add 2)
~zod/try=> (mol 4)
6
~zod/try=> (mol 7)
9

++curr

++  curr
  |*  [a=_|=(^ _*) c=*]
  |*  b=_+<+.a
  (a b c)

Right curry a gate, binding the tail of its sample

a is a gate.

c is a noun.

~zod/try=> =tep (curr scan sym)
~zod/try=> `@t`(tep "asd")
'asd'
~zod/try=> `@t`(tep "lek-om")
'lek-om'

++cork

++  cork  |*([a=_,* b=gate] (corl b a))                 ::  compose forward

Build f such that (f x) .= (b (a x)).

a is a noun.

b is a gate.

~zod/try=> (:(cork dec dec dec) 20)
17
~zod/try=> =mal (mo (limo a/15 b/23 ~))
~zod/try=> ((cork ~(got by mal) dec) %a)
14
~zod/try=> ((cork ~(got by mal) dec) %b)
22

++corl

++  corl                                                ::  compose backwards
  |*  [a=gate b=_,*]
  |=  c=_+<.b
  (a (b c))

Gate compose

XX Revisit

a is a gate.

b is a noun.

~zod/try=> ((corl (lift bex) (slat %ud)) '2')
[~ 4]

++hard

++  hard
  |*  han=$+(* *)
  |=  fud=*  ^-  han
  ~|  %hard
  =+  gol=(han fud)
  ?>(=(gol fud) gol)

Demands that a specific type be produced, crashing the program is it is not.

~zod/try=> ((hard (list)) (limo [1 2 3 ~]))
~[1 2 3]
~zod/try=> ((hard ,@) (add 2 2))
4
~zod/try=> ((hard ,@t) (crip "Tape to cord, bro!"))
'Tape to cord, bro'
~zod/try=> ((hard tape) (crip "...Tape to cord, bro?..."))
! hard
! exit

++soft

++  soft
  |*  han=$+(* *)
  |=  fud=*  ^-  (unit han)
  =+  gol=(han fud)
  ?.(=(gol fud) ~ [~ gol])

Politely requests a specific type to be produced, producing null if it is not.

~zod/try=> ((soft ,%4) (add 2 2))
[~ %4]
~zod/try=> ((soft ,@) (add 2 2))
[~ 4]
~zod/try=> ((soft ,%5) (add 2 2))
~
~zod/try=> ((soft ,@t) (crip "Tape to cord, Woohoo!"))
[~ 'Tape to cord, Woohoo!']
~zod/try=> ((soft ,@t) (trip 'Cmon man... Tape to cord? Please?!'))
~