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]