urbit/docs/pub/doc/hoon/library/2b.md
Galen Wolfe-Pauly ec2b8f56fd doc -> docs
2015-02-24 11:33:50 -08:00

898 lines
21 KiB
Markdown

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 `a`and 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 [atom]()s.
`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 [list]()s.
~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 [list]()s.
~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 [list]()s.
~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]