urbit/base/pub/doc/hoon/library/2b.md
Anton Dyudin 6cbb6b060d Revert "remove docs for demo", "remove odds and ends", "demo network", "DEMO ONLY: root beak as %demo.", "DEMO ONLY: don't show doznec flapping.", "Prinrtf."
This reverts commit 8e1e40d75b3ab15c194b6bf9570f3edc46e2de58.
This reverts commit f073c490f9fd7c5abc033af4857df92229877de7.
This reverts commit f187d2d7e01a54823f3e979af9bbd148b398e7e9.
This reverts commit bc272862a73cfce1b118586ca39d3a377d841f1b.
This reverts commit 30a397513f8890a3406dc7ab91c6e067e3bbfbbb.
This reverts commit 4fc6856fb50d88c20a0f533392ca606641c5f38f.

Conflicts:
	urb/urbit.pill
	urb/zod/base/lib/drum.hoon
2015-06-15 18:10:02 -07:00

22 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]