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]