:>    basic containers
|%
::
++  first
  |*  a=^
  -.a
::
++  second
  |*  a=^
  +.a
::
++  either  |*([a=mold b=mold] $%({$& p/a} {$| p/b}))   ::  either
::
++  thr
  |%
  ++  apply
    :>  applies {b} {a} is first, or {b} to {a} is second.
    |*  [a=(either) b=$-(* *) c=$-(* *)]
    ?-  -.a
      $&  (b p.a)
      $|  (c p.a)
    ==
  ::
  ++  firsts
    :>  returns a list of all first elements in {a}.
    |*  a=(list (either))
    =>  .(a (homo a))
    |-
    ?~  a
      ~
    ?-  -.i.a
      $&  [p.i.a $(a t.a)]
      $|  $(a t.a)
    ==
  ::
  ++  seconds
    :>  returns a list of all second elements in {a}.
    |*  a=(list (either))
    =>  .(a (homo a))
    |-
    ?~  a
      ~
    ?-  -.i.a
      $&  $(a t.a)
      $|  [p.i.a $(a t.a)]
    ==
  ::
  ++  partition
    :>  splits the list of eithers into two lists based on first or second.
    |*  a=(list (either))
    =>  .(a (homo a))
    |-
    ^-  {(list _?>(?=({{%& *} *} a) p.i.a)) (list _?>(?=({{%| *} *} a) p.i.a))}
    ?~  a
      [~ ~]
    =+  ret=$(a t.a)
    ?-  -.i.a
      $&  [[p.i.a -.ret] +.ret]
      $|  [-.ret [p.i.a +.ret]]
    ==
  --
++  maybe  |*(a=mold $@($~ {$~ u/a}))                   ::  maybe
++  myb
  |%
  ++  is-null
    :>    returns %.y if maybe is null.
    :>
    :>  corresponds to {isJust} in haskell.
    |*  a=(maybe)
    :>  whether {a} is null.
    ?~  a  %.y
    %.n
  ::
  ++  exists
    :>    returns %.y if maybe contains a real value.
    :>
    :>  corresponds to {isNothing} in haskell.
    |*  a=(maybe)
    :>  whether {a} is not null.
    ?~  a  %.n
    %.y
  ::
  ++  need
    :>    returns the value or crashes.
    :>
    :>  corresponds to {fromJust} in haskell.
    |*  a=(maybe)
    ?~  a  ~>(%mean.[%leaf "need"] !!)
    :>  the value from the maybe.
    u.a
  ::
  ++  default
    :>    returns the value in the maybe, or a default value on null.
    :>
    :>  corresponds to {fromMaybe} in haskell.
    |*  [a=(maybe) b=*]
    ?~(a b u.a)
  ::
  ++  from-list
    :>    returns the first value of the list, or null on empty list.
    :>
    :>  corresponds to {listToMaybe} in haskell.
    |*  a=(list)
    ^-  (maybe _i.a)
    ?~  a  ~
    [~ i.a]
  ::
  ++  to-list
    :>    converts the maybe to a list.
    :>
    :>  corresponds to {maybeToList} in haskell.
    |*  a=(maybe)
    ^-  (list _u.a)
    ?~  a  ~
    [u.a ~]
  ::
  ++  concat
    :>    converts a list of maybes to a list of non-null values.
    :>
    :>  corresponds to {catMaybes} in haskell.
    |*  a=(list (maybe))
    =>  .(a (homo a))
    |-
    ^-  (list _u.+.i.-.a)
    ?~  a  ~
    ?~  i.a
      $(a t.a)
    [u.i.a $(a t.a)]
  ::
  ++  map
    :>    a version of map that can throw out items.
    :>
    :>  takes a list of items and a function of the type
    :>
    :>  todo: while this was in Data.Maybe in haskell, this might better
    :>  logically be put in our list class? murn is.
    :>
    :>  corresponds to {mapMaybes} in haskell.
    |*  [a=(list) b=$-(* (maybe))]
    =>  .(a (homo a))
    |-
    ^-  (list _,.+:*b)
    ?~  a  ~
    =+  c=(b i.a)
    ?~  c
      $(a t.a)
    ::  todo: the span of c does not have the faces of a maybe. how do i either
    ::  force a resurface or act safely on the incoming?
    [+.c $(a t.a)]
  ::
  ++  apply
    :>  applies {b} to {a}.
    |*  [a=(maybe) b=$-(* (maybe))]
    ?~  a  ~
    (b u.a)
  ::
  ::  todo: bind, bond, both, flit, hunt, lift, mate,
  ::
  ::  used in other files: bond, drop (but only once)
  ::  unusued: clap
  --
++  ls
  ::  we are back to a basic problem here: when we try to pass lists without
  ::  {i} and {t} faces, we have to use {-} and {+} to access the structure of
  ::  the list. but we then can't deal with incoming lists that do have faces,
  ::  as `+:[i="one" t=~]` is `t=~`, not `~`.
  ::
  ::  what i really want is that the sapn outside a |* is `{"" 2 "" $~}`, but
  ::  inside, it is `(list $?(@ud tape))`. all of a sudden, you don't need
  ::  ++limo or ++homo, because you have the right span from the beginning!
  ::  those two functions really feel like they're working around the type
  ::  system instead of cooperating with it.
  ::
  :>  list utilities
  |%
  :>  #  %basic
  :>    basic list manipulation
  +|
  ::
  ++  head
    :>  returns the first item in the list, which must be non-empty.
    |*  a=(list)
    =>  .(a (homo a))
    :>  the first item in the list.
    ?~  a  ~>(%mean.[%leaf "head"] !!)
    i.a
  ::
  ++  last
    :>  returns the final item in the list, which must be non-empty.
    |*  a=(list)
    :>  the last item in a list.
    ?~  a  ~>(%mean.[%leaf "last"] !!)
    ?~  t.a
      i.a
    $(a t.a)
  ::
  ++  tail
    :>  returns all items after the head of the list, which must be non-empty.
    |*  a=(list)
    ^+  a
    ?~  a  ~>(%mean.[%leaf "tail"] !!)
    t.a
  ::
  ++  init
    :>  returns all items in the list except the last one. must be non-empty.
    |*  a=(list)
    =>  .(a (homo a))
    |-
    ^+  a
    ?~  a  ~>(%mean.[%leaf "init"] !!)
    |-
    ?~  t.a
      ~
    [i.a $(a t.a)]
::    ::
::    ::  ommitted: uncons, null
::    ::
  ++  size
    :>    returns the number of items in {a}.
    :>
    :>  corresponds to {length} in haskell.
    |=  a=(list)
    =|  b=@u
    ^-  @u
    |-
    ?~  a
      b
    $(a t.a, b +(b))
  ::
  :>  #  %transformations
  :>    functions which change a list into another list
  +|
  ::
  ++  map
    :>  applies a gate to each item in the list.
    |*  [a=(list) b=$-(* *)]
    ^-  (list _*b)
    ?~  a  ~
    [(b i.a) $(a t.a)]
  ::
  ++  reverse
    :>  reverses the order of the items in the list.
    |*  a=(list)
    =>  .(a (homo a))
    ^+  a
    =+  b=`_a`~
    |-
    ?~  a  b
    $(a t.a, b [i.a b])
  ::
  ++  intersperse
    :>  places {a} between each element in {b}.
    |*  [a=* b=(list)]
    =>  .(b (homo b))
    |-
    ^+  (homo [a b])
    ?~  b
      ~
    =+  c=$(b t.b)
    ?~  c
      [i.b ~]
    [i.b a c]
  ::
  ++  intercalate
    :>  places {a} between each list in {b}, and flatten to a single list.
    |*  [a=(list) b=(list (list))]
    =>  .(a ^.(homo a), b ^.(homo b))
    |-
    ^+  (concat [a b])
    ?~  b
      ~
    =+  c=$(b t.b)
    ?~  c
      i.b
    :(weld i.b a c)
  ::
  ++  transpose
    :>  transposes rows and columns of a 2d list structure.
    |*  input=(list (list))
    ::  todo: this should homogenize with each sublist.
    ^-  (list (list))
    =/  items
      %^  foldl  input  `{(list) (list (list))}`[~ ~]
      |=  :>  current: the list of first items under construction.
          :>  remaining: the remaining item lists.
          :>  next: the next list in {input}.
          {state/{current/(list) remaining/(list (list))} next/(list)}
      ?~  next
        state
      ?~  t.next
        [[i.next current.state] remaining.state]
      [[i.next current.state] [t.next remaining.state]]
    ?~  +.items
      `(list (list))`[(reverse -.items) ~]
    [(reverse -.items) $(input (reverse +.items))]
  ::
::    ::  ++  subsequences
::    ::    |=  a=(list)
::    ::    ?~  a
::    ::      ~
::    ::    :-  -.a
::    ::    %^  foldr
::    ::    $(a +.a)
::    ::    `(list)`~
::    ::    |=  [ys=(list) r=(list)]
::    ::    ~ ::[ys [-.a ys] r ~]
::    ::  TODO:
::    ::  ++subsequences
::    ::  ++permutations

  ::
  :>  #  %folds
  :>    functions which reduce a list to a value
  +|
  ::
  ++  foldl
    :>    left associative fold
    :>
    :>  this follows haskell giving an explicit starting value instead of {roll}.
    |*  [a=(list) b=* c=$-({* *} *)]
    ^+  b
    ?~  a
      b
    $(a t.a, b (c b i.a))
  ::
  ++  foldr
    :>  right associative fold
    |*  [a=(list) b=* c=$-({* *} *)]
    ^+  b
    ?~  a
      b
    (c $(a t.a) i.a)
  ::
  ++  concat
    :>  concatenate a list of lists into a single level.
    |*  a=(list (list))
    =>  .(a ^.(homo a))
    |-  ^+  (homo i:-.a)
    ?~  a
      ~
    (weld (homo i.a) $(a t.a))
  ::
  ++  weld
    :>  combine two lists, possibly of different types.
    |*  [a=(list) b=(list)]
    =>  .(a ^.(homo a), b ^.(homo b))
    |-  ^-  (list $?(_i.-.a _i.-.b))
    ?~  a  b
    [i.a $(a t.a)]
  ::
  ++  any
    :>  returns yes if any element satisfies the predicate
    |*  [a=(list) b=$-(* ?)]
    ?~  a
      %.n
    ?|((b i.a) $(a t.a))
  ::
  ++  all
    :>  returns yes if all elements satisfy the predicate
    |*  [a=(list) b=$-(* ?)]
    ?~  a
      %.y
    ?&((b i.a) $(a t.a))
  ::
  ::  haskell has a bunch of methods like sum or maximum which leverage type
  ::  classes, but I don't think they can be written generically in hoon.
  ::
  ::
  :>  #  %building
  :>    functions which build lists
  +|
  ++  scanl
    :>  returns a list of successive reduced values from the left.
    |*  [a=(list) b=* c=$-({* *} *)]
    =>  .(a (homo a))
    |-
    ?~  a
      [b ~]
    [b $(a t.a, b (c b i.a))]
  ::
  ++  scanl1
    :>  a variant of ++scanl that has no starting value.
    |*  [a=(list) c=$-({* *} *)]
    =>  .(a (homo a))
    |-
    ?~  a
      ~
    ?~  t.a
      ~
    (scanl t.a i.a c)
  ::
  ++  scanr
    :>  the right-to-left version of scanl.
    |*  [a=(list) b=* c=$-({* *} *)]
    =>  .(a (homo a))
    |-
    ^-  (list _b)
    ?~  a
      [b ~]
    =+  rest=$(a t.a)
    ?>  ?=(^ rest)
    [(c i.a i.rest) rest]
  ::
  ++  scanr1
    :>  a variant of ++scanr that has no starting value.
    |*  [a=(list) c=$-({* *} *)]
    =>  .(a (homo a))
    |-
    ^+  a
    ?~  a
      ~
    ?~  t.a
      [i.a ~]
    =+  rest=$(a t.a)
    ?>  ?=(^ rest)
    [(c i.a i.rest) rest]
  ::
  ++  map-foldl
    :>    performs both a ++map and a ++foldl in one pass.
    :>
    :>  corresponds to {mapAccumL} in haskell.
    |*  [a=(list) b=* c=$-({* *} {* *})]
    ^-  {_b (list _+:*c)}
    ?~  a
      [b ~]
    =+  d=(c b i.a)
    =+  recurse=$(a t.a, b -.d)
    [-.recurse [+.d +.recurse]]
  ::
  ++  map-foldr
    :>    performs both a ++map and a ++foldr in one pass.
    :>
    :>  corresponds to {mapAccumR} in haskell.
    |*  [a=(list) b=* c=$-({* *} {* *})]
    ^-  {_b (list _+:*c)}
    ?~  a
      [b ~]
    =+  recurse=$(a t.a)
    =+  d=(c -.recurse i.a)
    [-.d [+.d +.recurse]]
  ::
  ++  unfoldr
    :>  generates a list from a seed value and a function.
    |*  [b=* c=$-(* (maybe {* *}))]
    |-
    ^-  (list _b)
    =+  current=(c b)
    ?~  current
      ~
    ::  todo: the span of {c} is resurfaced to have a u. this might do funky
    ::  things with faces.
    [-.+.current $(b +.+.current)]
  ::
  :>  #  %sublists
  :>    functions which return a portion of the list
  +|
  ::
  ++  take
    :>  returns the first {a} elements of {b}.
    |*  [a=@ b=(list)]
    =>  .(b (homo b))
    |-
    ^+  b
    ?:  =(0 a)
      ~
    ?~  b
      ~
    [i.b $(a (dec a), b +.b)]
  ::
  ++  drop
    :>  returns {b} without the first {a} elements.
    |*  [a=@ b=(list)]
    ?:  =(0 a)
      b
    ?~  b
      b
    $(a (dec a), b +.b)
  ::
  ++  split-at
    :>  returns {b} split into two lists at the {a}th element.
    |*  [a=@ b=(list)]
    =>  .(b (homo b))
    |-
    ^+  [b b]
    ?:  =(0 a)
      [~ b]
    ?~  b
      [~ b]
    =+  d=$(a (dec a), b t.b)
    [[i.b -.d] +.d]
  ::
  ++  take-while
    :>  returns elements from {a} until {b} returns %.no.
    |*  [a=(list) b=$-(* ?)]
    =>  .(a (homo a))
    |-
    ^+  a
    ?~  a
      ~
    ?.  (b -.a)
      ~
    [i.a $(a t.a)]
  ::
  ++  drop-while
    :>  returns elements form {a} once {b} returns %.no.
    |*  [a=(list) b=$-(* ?)]
    =>  .(a (homo a))
    |-
    ?~  a
      ~
    ?.  (b i.a)
      a
    $(a t.a)
  ::
  ++  drop-while-end
    :>  drops the largest suffix of {a} which matches {b}.
    |*  [a=(list) b=$-(* ?)]
    =>  .(a (homo a))
    |-
    ?~  a
      ~
    =+  r=$(a t.a)
    ?:  ?&(=(r ~) (b i.a))
      ~
    [i.a r]
  ::
  ++  split-on
    :>    returns [the longest prefix of {b}, the rest of the list].
    :>
    :>  corresponds to {span} in haskell. renamed to not conflict with hoon.
    |*  [a=(list) b=$-(* ?)]
    =>  .(a (homo a))
    |-
    ^+  [a a]
    ?~  a
      [~ ~]
    ?.  (b i.a)
      [~ a]
    =+  d=$(a +.a)
    [[i.a -.d] +.d]
  ::
  ++  break
    :>  like {split-on}, but reverses the return code of {b}.
    |*  [a=(list) b=$-(* ?)]
    =>  .(a (homo a))
    |-
    ^+  [a a]
    ?~  a
      [~ ~]
    ?:  (b i.a)
      [~ a]
    =+  d=$(a t.a)
    [[i.a -.d] +.d]
  ::
  ++  strip-prefix
    :>  returns a {maybe} of {b} with the prefix {a} removed, or ~ if no match.
    |*  [a=(list) b=(list)]
    ^-  (maybe _b)
    ?~  a
      `b
    ?~  b
      ~
    $(a +.a, b +.b)
  ::
  :: todo: ++group
  ::
  ++  inits
    :>    returns all initial segments in reverse order.
    :>
    :>  unlike haskell, this does not return the empty list as the first
    :>  element, as hoon uses null as the list terminator.
    |*  a=(list)
    =>  .(a (homo a))
    %-  flop
    |-
    ?~  a  ~
    [a $(a (init a))]
  ::
  ++  tails
    :>  returns all final segments, longest first.
    |*  a=(list)
    =>  .(a (homo a))
    |-
    ?~  a  ~
    [a $(a t.a)]
  ::
  :>  #  %predicates
  :>    functions which compare lists
  +|
  ::
  ++  is-prefix-of
    :>  returns %.y if the first list is a prefix of the second.
    |*  [a=(list) b=(list)]
    =>  .(a (homo a), b (homo b))
    |-
    ^-  ?
    ?~  a
      %.y
    ?~  b
      %.n
    ?.  =(i.a i.b)
      %.n
    $(a t.a, b t.b)
  ::
  ++  is-suffix-of
    :>  returns %.y if the first list is the suffix of the second.
    |*  [a=(list) b=(list)]
    =>  .(a (homo a), b (homo b))
    ^-  ?
    ::  todo: this is performant in haskell because of laziness but may not be
    ::  adequate in hoon.
    (is-prefix-of (reverse a) (reverse b))
  ::
  ++  is-infix-of
    :>  returns %.y if the first list appears anywhere in the second.
    |*  [a=(list) b=(list)]
    =>  .(a (homo a), b (homo b))
    |-
    ^-  ?
    ?~  a
      %.y
    ?~  b
      %.n
    ?:  (is-prefix-of a b)
      %.y
    $(b t.b)
  ::
  :: todo: ++is-subsequence-of
  ::
  :>  #  %searching
  :>    finding items in lists
  ::
  ++  elem
    :>  does {a} occur in list {b}?
    |*  [a=* b=(list)]
    ?~  b
      %.n
    ?:  =(a i.b)
      %.y
    $(b t.b)
  ::
  ++  lookup
    :>  looks up the key {a} in the association list {b}
    |*  [a=* b=(list (pair))]
    ^-  (maybe _+.-.b)
    ?~  b
      ~
    ?:  =(a p.i.b)
      [~ q.i.b]
    $(b t.b)
  ::
  ++  find
    :>  returns the first element of {a} which matches predicate {b}.
    |*  [a=(list) b=$-(* ?)]
    ^-  (maybe _-.a)
    ?~  a
      ~
    ?:  (b i.a)
      [~ i.a]
    $(a t.a)
  ::
  ++  filter
    :>  filter all items in {a} which match predicate {b}.
    |*  [a=(list) b=$-(* ?)]
    =>  .(a (homo a))
    |-
    ^+  a
    ?~  a
      ~
    ?.  (b i.a)
      [i.a $(a t.a)]
    $(a t.a)
  ::
  ++  partition
    :>  returns two lists, one whose elements match {b}, the other which doesn't.
    |*  [a=(list) b=$-(* ?)]
    =>  .(a (homo a))
    |-
    ^+  [a a]
    ?~  a
      [~ ~]
    =+  rest=$(a t.a)
    ?:  (b i.a)
      [[i.a -.rest] +.rest]
    [-.rest [i.a +.rest]]
  ::
  :>  #  %indexing
  :>    finding indices in lists
  +|
  ::
  ++  elem-index
    :>  returns {maybe} the first occurrence of {a} occur in list {b}.
    =|  i=@u
    |=  [a=* b=(list)]
    ^-  (maybe @ud)
    ?~  b
      ~
    ?:  =(a i.b)
      `i
    $(b t.b, i +(i))
  ::
  ++  elem-indices
    :>  returns a list of indices of all occurrences of {a} in {b}.
    =|  i/@u
    |=  [a=* b=(list)]
    ^-  (list @ud)
    ?~  b
      ~
    ?:  =(a i.b)
      [i $(b t.b, i +(i))]
    $(b t.b, i +(i))
  ::
  ++  find-index
    :>  returns {maybe} the first occurrence which matches {b} in {a}.
    =|  i=@u
    |*  [a=(list) b=$-(* ?)]
    ^-  (maybe @ud)
    ?~  a
      ~
    ?:  (b i.a)
      `i
    $(a t.a, i +(i))
  ::
  ++  find-indices
    :>  returns a list of indices of all items in {a} which match {b}.
    =|  i=@u
    |*  [a=(list) b=$-(* ?)]
    ^-  (list @ud)
    ?~  a
      ~
    ?:  (b i.a)
      [i $(a t.a, i +(i))]
    $(a t.a, i +(i))
  ::
  ++  zip
    :>  takes a list of lists, returning a list of each first items.
    |*  a=(list (list))
    =>  .(a (multi-homo a))
    |^  ^+  a
        ?~  a  ~
        ?.  valid
          ~
        =+  h=heads
        ?~  h  ~
        [heads $(a tails)]
    ::
    ++  valid
      %+  all  a
      |=  next=(list)
      ?~  a  %.n
      %.y
    ::
    ++  heads
      ^+  (homo i:-.a)
      |-
      ?~  a  ~
      ?~  i.a  ~
      [i.i.a $(a t.a)]
    ::
    ++  tails
      ^+  a
      |-
      ?~  a  ~
      ?~  i.a  ~
      [t.i.a $(a t.a)]
    --
  ++  multi-homo
    |*  a=(list (list))
    ^+  =<  $
      |%  +-  $  ?:(*? ~ [i=(homo (snag 0 a)) t=$])
      --
    a
  ::
  :>  #  %set
  :>    set operations on lists
  +|
  ++  unique
    :>    removes duplicates elements from {a}
    :>
    :>  corresponds to {nub} in haskell.
    |*  a=(list)
    =>  .(a (homo a))
    =|  seen/(list)
    ^+  a
    |-
    ?~  a
      ~
    ?:  (elem i.a seen)
      $(a t.a)
    [i.a $(seen [i.a seen], a t.a)]
  ::
  ++  delete
    :>  removes the first occurrence of {a} in {b}
    |*  [a=* b=(list)]
    =>  .(b (homo b))
    ^+  b
    |-
    ?~  b
      ~
    ?:  =(a i.b)
      t.b
    [i.b $(b t.b)]
  ::
  ++  delete-firsts
    :>  deletes the first occurrence of each element in {b} from {a}.
    |*  [a=(list) b=(list)]
    =>  .(a (homo a), b (homo b))
    |-
    ^+  a
    ?~  a
      ~
    ?~  b
      a
    ?:  (elem i.a b)
      $(a t.a, b (delete i.a b))
    [i.a $(a t.a)]
  ::
  ++  union
    :>  the list union of {a} and {b}.
    |*  [a=(list) b=(list)]
    =>  .(a (homo a), b (homo b))
    |-
    ^+  (weld a b)
    ?~  a
      b
    ?~  b
      ~
    [i.a $(a t.a, b (delete i.a b))]
  ::
  ++  intersect
    :>  the intersection of {a} and {b}.
    |*  [a=(list) b=(list)]
    =>  .(a (homo a), b (homo b))
    |-
    ^+  a
    ?~  a
      ~
    ?:  (elem i.a b)
      [i.a $(a t.a)]
    $(a t.a)
  ::
  ::  todo: everything about ++sort and ++sort-on needs more thought. the
  ::  haskell implementation uses the Ord typeclass to sort things by
  ::  default. ++sort as is is probably the correct thing to do.
  ::
  --
::
++  dict
  :>    a dictionary mapping keys of {a} to values of {b}.
  :>
  :>  a dictionary is treap ordered; it builds a treap out of the hashed key
  :>  values.
  |*  [a=mold b=mold]
  %+  cork  (tree (pair a b))
  |=  c/(tree (pair a b))  ^+  c
  ?.((valid:dct c) ~ c)
::
++  dct
  |%
  :>  #  %query
  :>    looks up values in the dict.
  +|
  ++  empty
    :>  is the dict empty?
    |*  a=(dict)
    ?~  a  %.y
    %.n
  ::
  ++  size
    :>    returns the number of elements in {a}.
    |=  a=(dict)
    ^-  @u
    ?~  a  0
    :(add 1 $(a l.a) $(a r.a))
  ::
  ++  member
    :>  returns %.y if {b} is a key in {a}.
    |=  [a=(dict) key=*]
    ^-  ?
    ?~  a  %.n
    ?|(=(key p.n.a) $(a l.a) $(a r.a))
  ::
  ++  get
    :>  grab value by key.
    |*  [a=(dict) key=*]
    ^-  (maybe _?>(?=(^ a) q.n.a))
    ::  ^-  {$@($~ {$~ u/_?>(?=(^ a) q.n.a)})}
    ?~  a
      ~
    ?:  =(key p.n.a)
      `q.n.a
    ?:  (gor key p.n.a)
      $(a l.a)
    $(a r.a)
  ::
::    ::  todo: is ++got the correct interface to have? Haskell has lookup which
::    ::  returns a Maybe and a findWithDefault which passes in a default value.
::    ++  got
::      :>  todo: move impl here.
::      :>  todo: is there a way to make b/_<><>.a ?
::      |*  [a=(dict) key=*]
::      (~(got by a) key)
  ::
  ::  todo: skipping several methods which rely on the the Ord typeclass, like
  ::  lookupLT.
  ::
  :>  #  %insertion
  +|
  ++  put
    :>    inserts a new key/value pair, replacing the current value if it exists.
    :>
    :>  corresponds to {insert} in haskell.
    |*  [a=(dict) key=* value=*]
    |-  ^+  a
    ?~  a
      [[key value] ~ ~]
    ?:  =(key p.n.a)
      ?:  =(value q.n.a)
        a
      [[key value] l.a r.a]
    ?:  (gor key p.n.a)
      =+  d=$(a l.a)
      ?>  ?=(^ d)
      ?:  (vor p.n.a p.n.d)
        [n.a d r.a]
      [n.d l.d [n.a r.d r.a]]
    =+  d=$(a r.a)
    ?>  ?=(^ d)
    ?:  (vor p.n.a p.n.d)
      [n.a l.a d]
    [n.d [n.a l.a l.d] r.d]
  ::
  ++  put-with
    :>    inserts {key}/{value}, applying {fun} if {key} already exists.
    :>
    :>  corresponds to {insertWith} in haskell.
    |*  [a=(dict) key=* value=* fun=$-({* *} *)]
    |-  ^+  a
    ?~  a
      [[key value] ~ ~]
    ?:  =(key p.n.a)
      ::  key already exists; use {fun} to resolve.
      [[key (fun q.n.a value)] l.a r.a]
    ?:  (gor key p.n.a)
      =+  d=$(a l.a)
      ?>  ?=(^ d)
      ?:  (vor p.n.a p.n.d)
        [n.a d r.a]
      [n.d l.d [n.a r.d r.a]]
    =+  d=$(a r.a)
    ?>  ?=(^ d)
    ?:  (vor p.n.a p.n.d)
      [n.a l.a d]
    [n.d [n.a l.a l.d] r.d]
  ::
  ++  put-with-key
    :>    inserts {key}/{value}, applying {fun} if {key} already exists.
    :>
    :>  corresponds to {insertWithKey} in haskell.
    |*  [a=(dict) key=* value=* fun=$-({* * *} *)]
    |-  ^+  a
    ?~  a
      [[key value] ~ ~]
    ?:  =(key p.n.a)
      ::  key already exists; use {fun} to resolve.
      [[key (fun p.n.a q.n.a value)] l.a r.a]
    ?:  (gor key p.n.a)
      =+  d=$(a l.a)
      ?>  ?=(^ d)
      ?:  (vor p.n.a p.n.d)
        [n.a d r.a]
      [n.d l.d [n.a r.d r.a]]
    =+  d=$(a r.a)
    ?>  ?=(^ d)
    ?:  (vor p.n.a p.n.d)
      [n.a l.a d]
    [n.d [n.a l.a l.d] r.d]
  ::
  ++  put-lookup-with-key
    :>    combines insertion with lookup in one pass.
    :>
    :>  corresponds to {insertLookupWithKey} in haskell.
    |*  [a=(dict) key=* value=* fun=$-({* * *} *)]
    |-  ^-  {(maybe _value) _a}
    ?~  a
      [~ [[key value] ~ ~]]
    ?:  =(key p.n.a)
      ::  key already exists; use {fun} to resolve.
      [`q.n.a [[key (fun p.n.a q.n.a value)] l.a r.a]]
    ?:  (gor key p.n.a)
      =+  rec=$(a l.a)
      =+  d=+.rec
      ?>  ?=(^ d)
      ?:  (vor p.n.a p.n.d)
        [-.rec [n.a d r.a]]
      [-.rec [n.d l.d [n.a r.d r.a]]]
    =+  rec=$(a r.a)
    =+  d=+.rec
    ?>  ?=(^ d)
    ?:  (vor p.n.a p.n.d)
      [-.rec [n.a l.a d]]
    [-.rec [n.d [n.a l.a l.d] r.d]]
  ::
  :>  #  %delete-update
  +|
  ::
  ++  delete
    :>  deletes entry at {key}.
    |*  [a=(dict) key=*]
    |-  ^+  a
    ?~  a
      ~
    ?.  =(key p.n.a)
      ?:  (gor key p.n.a)
        [n.a $(a l.a) r.a]
      [n.a l.a $(a r.a)]
    (pop-top a)
  ::
  ++  adjust
    :>  updates a value at {key} by passing the value to {fun}.
    |*  [a=(dict) key=* fun=$-(* *)]
    %^  alter-with-key  a  key
    |=  [key=_p.-.n.-.a value=(maybe _q.+.n.-.a)]
    ^-  (maybe _q.+.n.-.a)
    ?~  value  ~
    [~ (fun u.value)]
  ::
  ++  adjust-with-key
    :>  updates a value at {key} by passing the key/value pair to {fun}.
    |*  [a=(dict) key=* fun=$-({* *} *)]
    %^  alter-with-key  a  key
    |=  [key=_p.-.n.-.a value=(maybe _q.+.n.-.a)]
    ^-  (maybe _q.+.n.-.a)
    ?~  value  ~
    [~ (fun key u.value)]
  ::
  ++  update
    :>  adjusts or deletes the value at {key} by {fun}.
    |*  [a=(dict) key=* fun=$-(* (maybe *))]
    %^  alter-with-key  a  key
    |=  [key=_p.-.n.-.a value=(maybe _q.+.n.-.a)]
    ^-  (maybe _q.+.n.-.a)
    ?~  value  ~
    (fun u.value)
  ::
  ++  update-with-key
    :>  adjusts or deletes the value at {key} by {fun}.
    |*  [a=(dict) key=* fun=$-({* *} (maybe *))]
    %^  alter-with-key  a  key
    |=  [key=_p.-.n.-.a value=(maybe _q.+.n.-.a)]
    ^-  (maybe _q.+.n.-.a)
    ?~  value  ~
    (fun key u.value)
  ::
  ::  todo:
  ::  ++update-lookup-with-key
  ::
  ++  alter
    :>  inserts, deletes, or updates a value by {fun}.
    |*  [a=(dict) key=* fun=$-((maybe *) (maybe *))]
    %^  alter-with-key  a  key
    |=  [key=_p.-.n.-.a value=(maybe _q.+.n.-.a)]
    (fun value)
  ::
  ++  alter-with-key
    :>  inserts, deletes, or updates a value by {fun}.
    |*  [a=(dict) key=* fun=$-({* (maybe *)} (maybe *))]
    |-  ^+  a
    ?~  a
      =+  ret=(fun key ~)
      ?~  ret
        ~
      [[key u.ret] ~ ~]
    ?:  =(key p.n.a)
      =+  ret=(fun key `q.n.a)
      ?~  ret
        (pop-top a)
      ?:  =(u.ret q.n.a)
        a
      [[key u.ret] l.a r.a]
    ?:  (gor key p.n.a)
      =+  d=$(a l.a)
      ?~  d
        [n.a ~ r.a]
      ?:  (vor p.n.a p.n.d)
        [n.a d r.a]
      [n.d l.d [n.a r.d r.a]]
    =+  d=$(a r.a)
    ?~  d
      [n.a l.a ~]
    ?:  (vor p.n.a p.n.d)
      [n.a l.a d]
    [n.d [n.a l.a l.d] r.d]
  ::
  :>  #  %combine
  +|
  ::
  ++  union
    :>  returns the union of {a} and {b}, preferring the value from {a} if dupe
    |*  [a=(dict) b=(dict)]
    |-  ^+  a
    ?~  b
      a
    ?~  a
      b
    ?:  (vor p.n.a p.n.b)
      ?:  =(p.n.b p.n.a)
        [n.a $(a l.a, b l.b) $(a r.a, b r.b)]
      ?:  (gor p.n.b p.n.a)
        $(a [n.a $(a l.a, b [n.b l.b ~]) r.a], b r.b)
      $(a [n.a l.a $(a r.a, b [n.b ~ r.b])], b l.b)
    ?:  =(p.n.a p.n.b)
      [n.b $(b l.b, a l.a) $(b r.b, a r.a)]
    ?:  (gor p.n.a p.n.b)
      $(b [n.b $(b l.b, a [n.a l.a ~]) r.b], a r.a)
    $(b [n.b l.b $(b r.b, a [n.a ~ r.a])], a l.a)
  ::
  ++  union-with
    :>  returns the union of {a} and {b}, running {fun} to resolve duplicates.
    |*  [a=(dict) b=(dict) fun=$-({* *} *)]
    |-  ^+  a
    ?~  b
      a
    ?~  a
      b
    ?:  (vor p.n.a p.n.b)
      ?:  =(p.n.b p.n.a)
        [[p.n.a (fun q.n.a q.n.b)] $(a l.a, b l.b) $(a r.a, b r.b)]
      ?:  (gor p.n.b p.n.a)
        $(a [n.a $(a l.a, b [n.b l.b ~]) r.a], b r.b)
      $(a [n.a l.a $(a r.a, b [n.b ~ r.b])], b l.b)
    ?:  =(p.n.a p.n.b)
      [n.b $(b l.b, a l.a) $(b r.b, a r.a)]
    ?:  (gor p.n.a p.n.b)
      $(b [n.b $(b l.b, a [n.a l.a ~]) r.b], a r.a)
    $(b [n.b l.b $(b r.b, a [n.a ~ r.a])], a l.a)
  ::
  ++  union-with-key
    :>  returns the union of {a} and {b}, running {fun} to resolve duplicates.
    |*  [a=(dict) b=(dict) fun=$-({* * *} *)]
    |-  ^+  a
    ?~  b
      a
    ?~  a
      b
    ?:  (vor p.n.a p.n.b)
      ?:  =(p.n.b p.n.a)
        [[p.n.a (fun p.n.a q.n.a q.n.b)] $(a l.a, b l.b) $(a r.a, b r.b)]
      ?:  (gor p.n.b p.n.a)
        $(a [n.a $(a l.a, b [n.b l.b ~]) r.a], b r.b)
      $(a [n.a l.a $(a r.a, b [n.b ~ r.b])], b l.b)
    ?:  =(p.n.a p.n.b)
      [n.b $(b l.b, a l.a) $(b r.b, a r.a)]
    ?:  (gor p.n.a p.n.b)
      $(b [n.b $(b l.b, a [n.a l.a ~]) r.b], a r.a)
    $(b [n.b l.b $(b r.b, a [n.a ~ r.a])], a l.a)
    ::
    ::  TODO: this is untested; move it.
::    ::
::    ++  difference
::      ::  todo: move real implementation here.
::      :>  returns elements in {a} that don't exist in {b}.
::      |*  [a=(dict) b=(dict)]
::      (~(dif by a) b)
::    ::
::    ::  todo:
::    ::  ++difference-with
::    ::  ++difference-with-key
::    ::
::    ++  intersection
::      ::  todo: move real implementation here.
::      :>  returns elements in {a} that exist in {b}.
::      |*  [a=(dict) b=(dict)]
::      (~(int by a) b)
::    ::
::    ::  todo:
::    ::  ++intersection-with
::    ::  ++intersection-with-key
  ::
  :>  #  %traversal
  +|
  ::
  ++  map
    :>  applies {fun} to each value in {a}.
    |*  [a=(dict) fun=$-(* *)]
    ^-  (dict _p.-.n.-.a fun)
    ?~  a
      ~
    [[p.n.a (fun q.n.a)] $(a l.a) $(a r.a)]
  ::
  ++  map-with-key
    :>  applies {fun} to each value in {a}.
    |*  [a=(dict) fun=$-({* *} *)]
    ^-  (dict _p.-.n.-.a _*fun)
    ?~  a
      ~
    [[p.n.a (fun p.n.a q.n.a)] $(a l.a) $(a r.a)]
  ::
  ++  map-fold
    :>    performs a fold on all the values in {a}.
    :>
    :>  lists have an order, but dicts are treaps. this means there isn't a
    :>  horizontal ordering, and thus the distinction between left and right
    :>  folding isn't relevant. your accumulator function will be called in
    :>  treap order.
    :>
    :>  corresponds to {mapAccum} in haskell.
    |*  [a=(dict) b=* fun=$-({* *} {* *})]
    ^-  {_b (dict _p.-.n.-.a _+:*fun)}
    ?~  a
      [b ~]
    =+  d=(fun b q.n.a)
    =.  q.n.a  +.d
    =+  e=$(a l.a, b -.d)
    =+  f=$(a r.a, b -.e)
    [-.f [n.a +.e +.f]]
  ::
  ++  map-keys
    :>  applies {fun} to all keys.
    ::  todo: the haskell version specifies that the "greatest" original key
    ::  wins in case of duplicates. this is currently unhandled. maybe i just
    ::  shouldn't have this gate.
    |*  [a=(dict) fun=$-(* *)]
    %-  from-list
    %+  map:ls  (to-list a)
    |=  item/_n.-.a
    [(fun p.item) q.item]
  ::
  ++  map-keys-with
    :>  applies {fun} to all keys, creating a new value with {combine} on dupes.
    |*  [a=(dict) fun=$-(* *) combine=$-({* *} *)]
    ^-  (dict _*fun _q.+.n.-.a)
    =/  new-list
      %+  map:ls  (to-list a)
      |=  item/_n.-.a
      [(fun p.item) q.item]
    %^  foldl:ls  new-list
    `(dict _*fun _q.+.n.-.a)`~
    |=  [m=(dict _*fun _q.+.n.-.a) p=_i.-.new-list]
    (put-with m -.p +.p combine)
  ::
  ++  fold
    :>    performs a fold on all the values in {a}.
    :>
    :>  lists have an order, but dicts are treaps. this means there isn't a
    :>  horizontal ordering, and thus the distinction between left and right
    :>  folding isn't relevant. your accumulator function will be called in
    :>  treap order.
    |*  [a=(dict) b=* fun=$-({* *} *)]
    ^-  _b
    ?~  a
      b
    =+  d=(fun b q.n.a)
    =+  e=$(a l.a, b d)
    $(a r.a, b e)
  ::
  ++  fold-with-keys
    :>    performs a fold on all the values in {a}, passing keys too.
    |*  [a=(dict) b=* fun=$-({* * *} *)]
    ^+  b
    ?~  a
      b
    =+  d=(fun b p.n.a q.n.a)
    =+  e=$(a l.a, b d)
    $(a r.a, b e)
  ::
  ++  any
    :>  returns yes if any element satisfies the predicate
    |*  [a=(dict) b=$-(* ?)]
    ^-  ?
    ?~  a
      %.n
    ?|((b q.n.a) $(a l.a) $(a r.a))
  ::
  ++  any-with-key
    :>  returns yes if any element satisfies the predicate
    |*  [a=(dict) b=$-({* *} ?)]
    ^-  ?
    ?~  a
      %.n
    ?|((b p.n.a q.n.a) $(a l.a) $(a r.a))
  ::
  ++  all
    :>  returns yes if all elements satisfy the predicate
    |*  [a=(dict) b=$-(* ?)]
    ^-  ?
    ?~  a
      %.y
    ?&((b q.n.a) $(a l.a) $(a r.a))
  ::
  ++  all-with-key
    :>  returns yes if all elements satisfy the predicate
    |*  [a=(dict) b=$-({* *} ?)]
    ^-  ?
    ?~  a
      %.y
    ?&((b p.n.a q.n.a) $(a l.a) $(a r.a))
  ::
  :>  #  %conversion
  +|
  ++  elems
    :>  return all values in the dict.
    |*  a=(dict)
    %+  turn  (to-list a)  second
  ::
  ++  keys
    :>  returns all keys in the dict.
    |*  a=(dict)
    %+  turn  (to-list a)  first
  ::
  ::  todo: ++assocs probably doesn't make sense when we have ++to-list and
  ::  when there's no general noun ordering.
  ::
  ++  keys-set
    :>  returns all keys as a set.
    |*  a=(dict)
    (si:nl (keys a))
  ::
  ++  from-set
    :>  computes a dict by running {fun} on every value in a set.
    |*  [a=(set) fun=$-(* *)]
    ^-  (dict _n.-.a _*fun)
    ?~  a
      ~
    [[n.a (fun n.a)] $(a l.a) $(a r.a)]
  ::
  :>  #  %lists
  +|
  ::
  ++  to-list
    :>  creates a list of pairs from the tree.
    |*  a=(dict)
    =|  b=(list _n.-.a)
    |-
    ^+  b
    ?~  a
      b
    $(a r.a, b [n.a $(a l.a)])
  ::
  ++  from-list
    :>  creates a tree from a list.
    |*  a=(list (pair))
    |-
    %^  foldl:ls  a
    `(dict _p.-.i.-.a _q.+.i.-.a)`~
    |=  [m=(dict _p.-.i.-.a _q.+.i.-.a) p=_i.-.a]
    (put m p)
  ::
  ++  from-list-with
    :>  creates a dict from a list, with {fun} resolving duplicates.
    |*  [a=(list (pair)) fun=$-(* *)]
    %^  foldl:ls  a
    `(dict _*fun _q.+.i.-.a)`~
    |=  [m=(dict _*fun _q.+.i.-.a) p=_i.-.a]
    (put-with m -.p +.p fun)
  ::
  ::  todo: without a natural ordering, association lists and gates to operate
  ::  on them probably don't make sense. i'm skipping them for now.
  ::
  :>  #  %filters
  +|
  ++  filter
    :>  filters a dict of all values that satisfy {fun}.
    |*  [a=(dict) fun=$-(* ?)]
    %+  filter-with-key  a
    |=  [key=* value=_q.+.n.-.a]
    (fun value)
  ::
  ++  filter-with-key
    :>  filters a dict of all values that satisfy {fun}.
    |*  [a=(dict) fun=$-({* *} ?)]
    |-
    ^+  a
    ?~  a  ~
    ?:  (fun n.a)
      =.  l.a  $(a l.a)
      =.  r.a  $(a r.a)
      (pop-top a)
    [n.a $(a l.a) $(a r.a)]
  ::
  ++  restrict-keys
    :>  returns a dict where the only allowable keys are {keys}.
    |*  [a=(dict) keys=(set)]
    %+  filter-with-key  a
    |=  [key=_p.-.n.-.a value=*]
    ::  todo: replace this with a call to our set library when we advance that
    ::  far.
    !(~(has in keys) key)
  ::
  ++  without-keys
    :>  returns a dict where the only allowable keys are not in {keys}.
    |*  [a=(dict) keys=(set)]
    %+  filter-with-key  a
    |=  [key=_p.-.n.-.a value=*]
    ::  todo: replace this with a call to our set library when we advance that
    ::  far.
    (~(has in keys) key)
  ::
  ++  partition
    :>  returns two lists, one whose elements match {fun}, the other doesn't.
    |*  [a=(dict) fun=$-(* ?)]
    ::  todo: is the runtime on this is bogus?
    =/  data
      %+  partition:ls  (to-list a)
      |=  p/_n.-.a
      (fun q.p)
    [(from-list -.data) (from-list +.data)]
  ::
  ::  todo:  ++partition-with-key once ++partition works.
  ::
  ::  i'm going to ignore all the Antitone functions; they don't seem to be
  ::  useful without ordering on the dict.
  ::
  ++  map-maybe
    :>  a version of map that can throw out items.
    |*  [a=(dict) fun=$-(* (maybe))]
    %+  map-maybe-with-key  a
    |=  [key=* value=_q.+.n.-.a]
    (fun value)
  ::
  ++  map-maybe-with-key
    :>  a version of map that can throw out items.
    |*  [a=(dict) fun=$-({* *} (maybe))]
    ^-  (dict _p.-.n.-.a _+:*fun)
    ?~  a  ~
    =+  res=(fun n.a)
    ?~  res
      =.  l.a  $(a l.a)
      =.  r.a  $(a r.a)
      (pop-top a)
    [[p.n.a +.res] $(a l.a) $(a r.a)]
  ::
  ++  map-either
    :>  splits the dict in two on a gate that returns an either.
    |*  [a=(dict) fun=$-(* (either))]
    %+  map-either-with-key  a
    |=  [key=* value=_q.+.n.-.a]
    (fun value)
  ::
  ++  map-either-with-key
    :>  splits the dict in two on a gate that returns an either.
    |*  [a=(dict) fun=$-({* *} (either))]
    |-
    ^-  $:  (dict _p.-.n.-.a _?>(?=({{%& *} *} *fun) +:*fun))
            (dict _p.-.n.-.a _?>(?=({{%| *} *} *fun) +:*fun))
        ==
    ?~  a
      [~ ~]
    ::  todo: runtime wise, can I do better than recursive unions?
    =+  lr=$(a l.a)
    =+  rr=$(a r.a)
    =+  x=(fun n.a)
    ~!  x
    ?-  -.x
      $&  [(put (union -.lr -.rr) p.n.a +.x) (union +.lr +.rr)]
      $|  [(union -.lr -.rr) (put (union +.lr +.rr) p.n.a +.x)]
    ==
  ::
  ::  ++split, ++split-lookup and ++split-root do not make sense without
  ::  ordinal keys.
  ::
  ++  is-subdict
    :>  returns %.y if every element in {a} exists in {b} with the same value.
    |*  [a=(dict) b=(dict)]
    ^-  ?
    (is-subdict-by a b |=([a=* b=*] =(a b)))
  ::
  ++  is-subdict-by
    :>  returns %.y if every element in {a} exists in {b} with the same value.
    |*  [a=(dict) b=(dict) fun=$-({* *} ?)]
    |-
    ^-  ?
    ?~  a  %.y
    ?~  b  %.n
    ~!  b
    ~!  p.n.a
    =+  x=(get b p.n.a)
    ?~  x  %.n
    |((fun q.n.a u.x) $(a l.a) $(a r.a))
  ::
  :>  #  %impl
  :>    implementation details
  +|
  ++  pop-top
    :>  removes the head of the tree and rebalances the tree below.
    |*  a=(dict)
    ^-  {$?($~ _a)}
    ?~  a  ~
    |-
    ?~  l.a  r.a
    ?~  r.a  l.a
    ?:  (vor p.n.l.a p.n.r.a)
      [n.l.a l.l.a $(l.a r.l.a)]
    [n.r.a $(r.a l.r.a) r.r.a]
  ::
  ++  valid
    :>  returns %.y if {a} if this tree is a valid treap dict.
    |*  a=(tree (pair * *))
    =|  [l=(maybe) r=(maybe)]
    |-  ^-  ?
    ?~  a   &
    ?&  ?~(l & (gor p.n.a u.l))
        ?~(r & (gor u.r p.n.a))
        ?~(l.a & ?&((vor p.n.a p.n.l.a) $(a l.a, l `p.n.a)))
        ?~(r.a & ?&((vor p.n.a p.n.r.a) $(a r.a, r `p.n.a)))
    ==
  --
++  random
  :>    produces a core which produces random numbers.
  :>
  :>  random numbers are generated through repeated sha-256 operations.
  :>
  :>  this design forces implementation details to be hidden, forces users to
  :>  go through =^. this should be less error prone for pulling out multiple
  :>  random numbers, at the cost of making getting a single random number
  :>  slightly more cumbersome.
  :>
  :>      =+  gen=(random eny)
  :>      =^  first  gen  (range:gen 0 10)
  :>      =^  second  gen  (range:gen 0 10)
  |=  a=@
  =>  |%
      ++  raw                                               ::  random bits
        |=  b=@  ^-  @
        %+  can
          0
        =+  c=(shas %og-a (mix b a))
        |-  ^-  (list {@ @})
        ?:  =(0 b)
          ~
        =+  d=(shas %og-b (mix b (mix a c)))
        ?:  (lth b 256)
          [[b (end 0 b d)] ~]
        [[256 d] $(c d, b (sub b 256))]
      ::
      ++  rad                                               ::  random in range
        |=  b=@  ^-  @
        =+  c=(raw (met 0 b))
        ?:((lth c b) c $(a +(a)))
      --
  ^?  |%
  ++  range
    :>  returns a random number in the range [start, end], and generator.
    |=  [start=@ end=@]
    ?:  (gte start end)
      ~_(leaf+"invalid range" !!)
    =+  offset=(sub end start)
    =+  r=(rad offset)
    [(add start r) +>.$(a (shas %og-s (mix a r)))]
  ::
  ++  bits
    :>  returns {b} bits in the range, and generator.
    |=  b=@
    =+  r=(raw b)
    [r +>.$(a (shas %og-s (mix a r)))]
  --
--