urbit/pub/docs/dev/hoon/library/2b.md
Galen Wolfe-Pauly bb495844be doc -> docs
2015-10-20 10:51:45 -07:00

21 KiB

chapter 2b, basic containers

Section 2bA, units

++biff

Unit as argument

++  biff                                                ::  apply
  |*  [a=(unit) b=$+(* (unit))]
  ?~  a  ~
  (b u.a)

Applies a gate that produces a unit, b, to the value (u.a) of a unit a. If a is empty, ~ is produced.

a is a unit.

b is a gate that accepts a noun and produces a unit.

~zod/try=> (biff (some 5) |=(a=@ (some (add a 2))))
[~ u=7]
~zod/try=> (biff ~ |=(a=@ (some (add a 2))))
~

++bind

Bind

++  bind                                                ::  argue
  |*  [a=(unit) b=gate]
  ?~  a  ~
  [~ u=(b u.a)]

Applies a function b to the value (u.a) of a unit a, producing a unit.

a is a unit

b is a gate.

~zod/try=> (bind ((unit ,@) [~ 97]) ,@t)
[~ `a`]
~zod/try=> =a |=(a=@ (add a 1))
~zod/try=> (bind ((unit ,@) [~ 2]) a)
[~ 3]

++bond

Replace null

++  bond                                                ::  replace
  |*  a=trap
  |*  b=(unit)
  ?~  b  $:a
  u.b

Replaces an empty unit b with the product of a kicked trap a. If the unit is not empty, then the original unit is produced.

a is a trap.

b is a unit.

~zod/try=> (bex 10)
1.024
~zod/try=> ((bond |.((bex 10))) ~)
1.024
~zod/try=> ((bond |.((bex 10))) (slaw %ud '123'))
123

++both

Group unit values

++  both                                                ::  all the above
  |*  [a=(unit) b=(unit)]
  ?~  a  ~
  ?~  b  ~
  [~ u=[u.a u.b]]

Produces a unit whose value is a cell of the values of two input units a and b. If either of the two units are empty, ~ is produced.

a is a unit.

b is a unit.

~zod/try=> (both (some 1) (some %b))
[~ u=[1 %b]]
~zod/try=> (both ~ (some %b))
~

++clap

Apply gate to two units

++  clap                                                ::  combine
  |*  [a=(unit) b=(unit) c=_|=(^ +<-)]
  ?~  a  b
  ?~  b  a
  [~ u=(c u.a u.b)]

Applies a binary operation c which produces a unit to the values of two units a and b.

a is a unit.

b is a unit.

c is a gate that performs a binary operation.

~zod/try=> =u ((unit ,@t) [~ 'a'])
~zod/try=> =v ((unit ,@t) [~ 'b'])
~zod/try=> (clap u v |=([a=@t b=@t] (welp (trip a) (trip b))))
[~ u="ab"] 
~zod/try=> =a ((unit ,@u) [~ 1])
~zod/try=> =b ((unit ,@u) [~ 2])
~zod/try=> =c |=([a=@ b=@] (add a b))
~zod/try=> (clap a b c)
[~ 3]

++drop

Unit list

++  drop                                                ::  enlist
  |*  a=(unit)
  ?~  a  ~
  [i=u.a t=~]

Produces a list of the value from a unit a.

a is a unit.

~zod/try=> =a ((unit ,@) [~ 97])
~zod/try=> (drop a)
[i=97 t=~] 
~zod/try=> =a ((unit ,@) [~])
~zod/try=> (drop a)
~

++fall

Default unit

++  fall                                                ::  default
  |*  [a=(unit) b=*]
  ?~(a b u.a)

Produces a default value b for a unit a in cases where the unit is null.

a is a unit.

b is a noun used as the default value.

~zod/try=> (fall ~ `a`)
`a`
~zod/try=> (fall [~ u=0] `a`)
0

++lift

Fmap

++  lift                                                ::  lift gate (fmap)
  |*  a=gate                                            ::  flipped
  |*  b=(unit)                                          ::  curried
  (bind b a)                                            ::  bind

Similar to fmap in Haskell: accepts a gate a that accepts and produces an unwrapped value, passes it the value of a unit b, and then produces a unit value.

a is a gate.

b is a unit.

~zod/try=> ((lift dec) `(unit ,@)`~)
~
~zod/try=> ((lift dec) `(unit ,@)`[~ 20])
[~ 19]

++mate

Choose

++  mate                                                ::  choose
  |*  [a=(unit) b=(unit)]
  ?~  b  a
  ?~  a  b
  ?.(=(u.a u.b) ~|('mate' !!) a)

Accepts two units a and b whose values are expected to be equivalent. If either is empty, then the value of the other is produced. If neither are empty, it asserts that both values are the same and produces that value. If the assertion fails, ++mate crashes with 'mate' in the stack trace.

a is a unit.

b is a unit.

~zod/try=> =a ((unit ,@) [~ 97])
~zod/try=> =b ((unit ,@) [~ 97])
~zod/try=> (mate a b)
[~ 97]
~zod/try=> =a ((unit ,@) [~ 97])
~zod/try=> =b ((unit ,@) [~])
~zod/try=> (mate a b)
[~ 97]
~zod/try=> =a ((unit ,@) [~ 97])
~zod/try=> =b ((unit ,@) [~ 98])
~zod/try=> (mate a b)
! 'mate'
! exit

++need

Unwrap

++  need                                                ::  demand
  |*  a=(unit)
  ?~  a  !!
  u.a

Retrieve the value from a unit and crash if the unit is null.

a is a unit.

~zod/try=> =a ((unit ,[@t @t]) [~ ['a' 'b']])
~zod/try=> (need a)
['a' 'b']
~zod/try=> =a ((unit ,@ud) [~ 17])
~zod/try=> (need a)
17
~zod/try=> =a ((unit ,@) [~])
~zod/try=> (need a)
! exit

++some

Unify

++  some                                                ::  lift (pure)
  |*  a=*
  [~ u=a]

Takes any atom a and produces a unit with the value set to a.

a is a noun.

~zod/try=> (some [`a` `b`])
[~ u=[`a` `b`]]
~zod/try=> (some &)
[~ u=%.y]

section 2bB, lists

Reverse

++flop

++  flop                                                ::  reverse
  ~/  %flop
  |*  a=(list)
  =>  .(a (homo a))
  ^+  a
  =+  b=`_a`~
  |-
  ?~  a  b
  $(a t.a, b [i.a b])

Produces the list a in reverse order.

a is a list.

~zod/try=> =a (limo [1 2 3 ~])
~zod/try=> (flop a)
~[3 2 1]

++homo

Homogenize

++  homo                                                ::  homogenize
  |*  a=(list)
  ^+  =<  $
    |%  +-  $  ?:(_? ~ [i=(snag 0 a) t=$])
    --
  a

Produces a list whose type is a fork of all the contained types in the list a.

a is a list.

~zod/try=> lyst
[i=1 t=[i=97 t=[i=2 t=[i=98 t=[i=[~ u=10] t=~]]]]]
~zod/try=> (homo lyst)
~[1 97 2 98 [~ u=10]]
~zod/try=> =a (limo [1 2 3 ~])
~zod/try=> a
[i=1 t=[i=2 t=[i=3 t=~]]]
~zod/try=> (homo a)
~[1 2 3]

++limo

List Constructor

++  limo                                                ::  listify
  |*  a=*
  ^+  =<  $
    |%  +-  $  ?~(a ~ ?:(_? i=-.a t=$ $(a +.a)))
    --
  a

Turns a null-terminated tuple into a list.

a is a null-terminated tuple.

~zod/try=> (limo [1 2 3 ~])
[i=1 t=[i=2 t=[i=3 t=~]]]

++lent

List length

++  lent                                                ::  length
  ~/  %lent
  |=  a=(list)
  ^-  @
  =+  b=0
  |-
  ?~  a  b 
  $(a t.a, b +(b))

Produces the length of any list a as an atom.

a is a list.

~zod/try=> (lent (limo [1 2 3 4 ~]))
4
~zod/try=> (lent (limo [1 'a' 2 'b' (some 10) ~]))
5

++levy

"and" to list

++  levy
  ~/  %levy                                             ::  all of
  |*  [a=(list) b=_|=(p=* .?(p))]
  |-  ^-  ?
  ?~  a  &
  ?.  (b i.a)  |
  $(a t.a)

Produces the Boolean "and" of the result of every element in list a passed to gate b.

a is a list.

b is a gate.

~zod/try=> =a |=(a=@ (lte a 1))
~zod/try=> (levy (limo [0 1 2 1 ~]) a)
%.n
~zod/try=> =a |=(a=@ (lte a 3))
~zod/try=> (levy (limo [0 1 2 1 ~]) a)
%.y

++lien

"or" to list

++  lien                                                ::  some of
  ~/  %lien
  |*  [a=(list) b=$+(* ?)]
  |-  ^-  ?
  ?~  a  |
  ?:  (b i.a)  &
  $(a t.a)

Produces the Boolean "or" of the result of every element in list a passed to gate b.

a is a list.

b is a gate.

~zod/try=> =a |=(a=@ (gte a 1))
~zod/try=> (lien (limo [0 1 2 1 ~]) a)
%.y
~zod/try=> =a |=(a=@ (gte a 3))
~zod/try=> (lien (limo [0 1 2 1 ~]) a)
%.n

++murn

Maybe transform

++  murn                                                ::  maybe transform
  |*  [a=(list) b=$+(* (unit))]
  |-
  ?~  a  ~
  =+  c=(b i.a)
  ?~  c
    $(a t.a)
  [i=u.c t=$(a t.a)]

Passes each member of list a to gate b, which must produce a unit. Produces a new list with all the results that do not produce ~.

a is a list.

b is a gate that produces a unit.

~zod/try=> =a |=(a=@ ?.((gte a 2) ~ (some (add a 10))))
~zod/try=> (murn (limo [0 1 2 3 ~]) a)
[i=12 t=[i=13 t=~]]

++reap

Replicate

++  reap                                                ::  replicate
  |*  [a=@ b=*]
  |-  ^-  (list ,_b)
  ?~  a  ~
  [b $(a (dec a))]

Replicate: produces a list containing a copies of b.

a is an atom

b is a noun

~zod/try=> (reap 20 %a)
~[%a %a %a %a %a %a %a %a %a %a %a %a %a %a %a %a %a %a %a %a]
~zod/try=> (reap 5 ~s1)
~[~s1 ~s1 ~s1 ~s1 ~s1]
~zod/try=> `@dr`(roll (reap 5 ~s1) add)
~s5

++reel

Right fold

++  reel                                                ::  right fold  
  ~/  %reel
  |*  [a=(list) b=_|=([* *] +<+)]
  |-  ^+  +<+.b
  ?~  a
    +<+.b
  (b i.a $(a t.a))

Right fold: moves right to left across a list a, recursively slamming a binary gate b with an element from a and an accumulator, producing the final value of the accumulator.

a is a list.

b is a binary gate.

~zod/try=> =sum =|([p=@ q=@] |.((add p q)))
~zod/try=> (reel (limo [1 2 3 4 5 ~]) sum)
15
~zod/try=> =a =|([p=@ q=@] |.((sub p q)))
~zod/try=> (reel (limo [6 3 1 ~]) a)
4
~zod/try=> (reel (limo [3 6 1 ~]) a)
! subtract-underflow
! exit

++roll

Left fold

++  roll                                                ::  left fold
  ~/  %roll
  |*  [a=(list) b=_|=([* *] +<+)]
  |-  ^+  +<+.b
  ?~  a
    +<+.b
  $(a t.a, b b(+<+ (b i.a +<+.b)))

Left fold: moves left to right across a list a, recursively slamming a binary gate b with an element from the list and an accumulator, producing the final value of the accumulator.

a is a list.

b is a binary gate.

~zod/try=> =sum =|([p=@ q=@] |.((add p q)))
~zod/try=> (roll (limo [1 2 3 4 5 ~]) sum)
q=15
~zod/try=> =a =|([p=@ q=@] |.((sub p q)))
~zod/try=> (roll (limo [6 3 1 ~]) a)
! subtract-underflow
! exit
~zod/try=> (roll (limo [1 3 6 ~]) a)
q=4

++skid

Separate

++  skid                                                ::  separate
  |*  [a=(list) b=$+(* ?)]
  |-  ^+  [p=a q=a]
  ?~  a  [~ ~]
  =+  c=$(a t.a)
  ?:((b i.a) [[i.a p.c] q.c] [p.c [i.a q.c]])

Seperates a list a into two lists - Those elements of a who produce true when slammed to gate b and those who produce %.n.

a is a list.

b is a gate that accepts one argument and produces a loobean.

~zod/try=> =a |=(a=@ (gth a 1))
~zod/try=> (skid (limo [0 1 2 3 ~]) a)
[p=[i=2 t=[i=3 t=~]] q=[i=0 t=[i=1 t=~]]]

++skim

Suffix

++  skim                                                ::  only
  ~/  %skim
  |*  [a=(list) b=_|=(p=* .?(p))]
  |-
  ^+  a
  ?~  a  ~
  ?:((b i.a) [i.a $(a t.a)] $(a t.a))

Cycles through the members of a list a, passing them to a gate b and producing a list of all of the members that produce %.y. Inverse of ++skip.

a is a list.

b is a gate that accepts one argument and produces a loobean.

~zod/try=> =a |=(a=@ (gth a 1))
~zod/try=> (skim (limo [0 1 2 3 ~]) a)
[i=2 t=[i=3 t=~]]

++skip

Except

++  skip                                                ::  except
  ~/  %skip
  |*  [a=(list) b=_|=(p=* .?(p))]
  |-
  ^+  a
  ?~  a  ~
  ?:((b i.a) $(a t.a) [i.a $(a t.a)])

Cycles through the members of a list a, passing them to a gate b and producing a list of all of the members that produce %.n. Inverse of ++skim.

a is a list.

b is a gate that accepts one argument and produces a loobean.

~zod/try=> =a |=(a=@ (gth a 1))
~zod/try=> (skip (limo [0 1 2 3 ~]) a)
[i=0 t=[i=1 t=~]]

++scag

Prefix

++  scag                                                ::  prefix
  ~/  %scag
  |*  [a=@ b=(list)]
  |-  ^+  b
  ?:  |(?=(~ b) =(0 a))  ~
  [i.b $(b t.b, a (dec a))]

Accepts an atom a and list b, producing the first a elements of the front of the list.

a is an atom.

b is a list.

~zod/try=> (scag 2 (limo [0 1 2 3 ~]))
[i=0 t=[i=1 t=~]]
~zod/try=> (scag 10 (limo [1 2 3 4 ~]))
[i=1 t=[i=2 t=[i=3 t=[i=4 t=~]]]]

++slag

Suffix

++  slag                                                ::  suffix
  ~/  %slag
  |*  [a=@ b=(list)]
  |-  ^+  b
  ?:  =(0 a)  b
  ?~  b  ~
  $(b t.b, a (dec a))

Accepts an atom a and list b, producing the remaining elements from b starting at a.

a is an atom.

b is a list.

~zod/try=> (slag 2 (limo [1 2 3 4 ~]))
[i=3 t=[i=4 t=~]]
~zod/try=> (slag 1 (limo [1 2 3 4 ~]))
[i=2 t=[i=3 t=[i=4 t=~]]]

++snag

Index

++  snag                                                ::  index
  ~/  %snag
  |*  [a=@ b=(list)]
  |-
  ?~  b
    ~|('snag-fail' !!)
  ?:  =(0 a)  i.b
  $(b t.b, a (dec a))

Accepts an atom a and a list b, producing the element at the index of aand failing if the list is null. Lists are 0-indexed.

a is an atom.

b is a list.

~zod/try=> (snag 2 "asdf")
~~d
~zod/try=> (snag 0 `(list ,@ud)`~[1 2 3 4])
1

++sort

Quicksort

++  sort                                                ::  quicksort
  ~/  %sort
  |*  [a=(list) b=$+([* *] ?)]
  =>  .(a ^.(homo a))
  |-  ^+  a
  ?~  a  ~
  %+  weld
    $(a (skim t.a |=(c=_i.a (b c i.a))))
  ^+  t.a
  [i.a $(a (skim t.a |=(c=_i.a !(b c i.a))))]

Quicksort: accepts a list a and a gate b which accepts two nouns and produces a loobean. ++sort then produces a list of the elements of a sorted according to b.

a is an atom.

b is a gate which accepts two nouns and produces a loobean.

    ~zod/try=> =a =|([p=@ q=@] |.((gth p q)))
    ~zod/try=> (sort (limo [0 1 2 3 ~]) a)
    ~[3 2 1 0]

++swag

Infix

++  swag                                                ::  infix
  |*  [[a=@ b=@] c=(list)]
  (scag b (slag a c))

Similar to substr in Javascript: extracts a string infix, beginning at inclusive index a, producing b number of characters.

a and b are atoms.

c is a list.

~zod/try=> (swag [2 5] "roly poly")
"ly po"
~zod/try=> (swag [2 2] (limo [1 2 3 4 ~]))
[i=3 t=[i=4 t=~]]

++turn

Gate to list

++  turn                                                ::  transform
  ~/  %turn
  |*  [a=(list) b=_,*]
  |-
  ?~  a  ~
  [i=(b i.a) t=$(a t.a)]

Accepts a list a and a gate b. Produces a list with the gate applied to each element of the original list.

a is a list.

b is a gate.

~zod/try=> (turn (limo [104 111 111 110 ~]) ,@t)
<|h o o n|>
~zod/try=> =a |=(a=@ (add a 4))
~zod/try=> (turn (limo [1 2 3 4 ~]) a)
~[5 6 7 8]

++weld

Concatenate

++  weld                                                ::  concatenate
  ~/  %weld
  |*  [a=(list) b=(list)]
  =>  .(a ^.(homo a), b ^.(homo b))
  |-  ^+  b
  ?~  a  b
  [i.a $(a t.a)]

Concatenate two lists a and b.

a and b are lists.

~zod/try=> (weld "urb" "it")
~[~~u ~~r ~~b ~~i ~~t]
~zod/try=> (weld (limo [1 2 ~]) (limo [3 4 ~]))
~[1 2 3 4]

++welp

Perfect weld

++  welp                                                ::  perfect weld
  =|  [* *]
  |%
  +-  $
    ?~  +<-
      +<-(. +<+)
    +<-(+ $(+<- +<->))
  --

Concatenate two lists a and b without losing their type information to homogenization.

a and b are lists.

~zod/try=> (welp "foo" "bar")
"foobar"
~zod/arvo=/hoon/hoon> (welp ~[60 61 62] ~[%a %b %c])
[60 61 62 %a %b %c ~]
~zod/arvo=/hoon/hoon> :type; (welp ~[60 61 62] ~[%a %b %c])
[60 61 62 %a %b %c ~]
[@ud @ud @ud %a %b %c %~]
~zod/arvo=/hoon/hoon> (welp [sa/1 so/2 ~] si/3)
[[%sa 1] [%so 2] %si 3]

++wild

XXDELETE

++  wild                                                ::  concatenate
  |*  [a=(list) b=(list)]
  =>  .(a ^.(homo a), b ^.(homo b))
  |-
  ?~  a  b
  [i=i.a $(a t.a)]

Concatenates two lists a and b, homogenizing their types individually.

a and b are lists.

~zod/try=> (wild (limo ~[1 2 3]) (limo [4]~))
~[1 2 3 4]
~zod/try=> (wild (limo 60 61 62 ~) (limo %a %b %c ~))
[i=60 [i=61 [i=62 ~[%a %b %c]]]]
~zod/try=> (weld (limo 60 61 62 ~) (limo %a %b %c ~))
! /~zod/arvo/~2014.10.2..22.58.23..5af9/hoon/:<[10.000 15].[10.016 57]>
! /~zod/arvo/~2014.10.2..22.58.23..5af9/hoon/:<[10.001 15].[10.016 57]>
! /~zod/arvo/~2014.10.2..22.58.23..5af9/hoon/:<[10.002 15].[10.016 57]>
! /~zod/arvo/~2014.10.2..22.58.23..5af9/hoon/:<[10.004 15].[10.016 57]>
! /~zod/arvo/~2014.10.2..22.58.23..5af9/hoon/:<[10.006 15].[10.016 57]>
! /~zod/arvo/~2014.10.2..22.58.23..5af9/hoon/:<[10.006 29].[10.006 44]>
! /~zod/arvo/~2014.10.2..22.58.23..5af9/hoon/:<[10.056 3].[10.061 13]>
! /~zod/arvo/~2014.10.2..22.58.23..5af9/hoon/:<[10.058 3].[10.061 13]>
! /~zod/arvo/~2014.10.2..22.58.23..5af9/hoon/:<[10.059 3].[10.061 13]>
! /~zod/arvo/~2014.10.2..22.58.23..5af9/hoon/:<[10.060 5].[10.060 47]>
! /~zod/arvo/~2014.10.2..22.58.23..5af9/hoon/:<[9.826 7].[9.844 35]>
! /~zod/arvo/~2014.10.2..22.58.23..5af9/hoon/:<[9.827 7].[9.844 35]>
! /~zod/arvo/~2014.10.2..22.58.23..5af9/hoon/:<[9.827 11].[9.838 13]>
! /~zod/arvo/~2014.10.2..22.58.23..5af9/hoon/:<[9.828 11].[9.838 13]>
! /~zod/arvo/~2014.10.2..22.58.23..5af9/hoon/:<[9.829 13].[9.831 47]>
! /~zod/arvo/~2014.10.2..22.58.23..5af9/hoon/:<[9.830 13].[9.831 47]>
! /~zod/arvo/~2014.10.2..22.58.23..5af9/hoon/:<[9.706 7].[9.712 25]>
! /~zod/arvo/~2014.10.2..22.58.23..5af9/hoon/:<[9.707 7].[9.712 25]>
! /~zod/arvo/~2014.10.2..22.58.23..5af9/hoon/:<[9.708 7].[9.712 25]>
! /~zod/arvo/~2014.10.2..22.58.23..5af9/hoon/:<[9.712 7].[9.712 25]>
! /~zod/arvo/~2014.10.2..22.58.23..5af9/hoon/:<[9.712 8].[9.712 25]>
! exit

++zing

Cons

++  zing                                                ::  promote
  =|  *
  |%
  +-  $
    ?~  +<
      +<
    (welp +<- $(+< +<+))
  --

Turns a list of lists into a single list by promoting the elements of each sublist into the higher.

Accepts a list of lists.

~zod/try=> (zing (limo [(limo ['a' 'b' 'c' ~]) (limo ['e' 'f' 'g' ~]) (limo ['h' 'i' 'j' ~]) ~]))
~['a' 'b' 'c' 'e' 'f' 'g' 'h' 'i' 'j']
~zod/try=> (zing (limo [(limo [1 'a' 2 'b' ~]) (limo [3 'c' 4 'd' ~]) ~]))
~[1 97 2 98 3 99 4 100]