anchor.diff:  //  
   //    But variables starting with '@' are global:
   //      {"asdf" | $>@x}{begin foo}{123 | $>@x || @x}{end foo}{@x}
  -
  -    
  -  
  + 
  +  
  +<h2>In Depth: Peek</h2>
  +
  +  This is a section all about how my list searching got flipped turned upside down. It includes the majority of the peek tests.
  +
  +  {* (:one :one :two :two :three :three) | $>numbers ||}
  +
  +  {* (:one :hashly :two :bashly :three :crashly) | $>hash ||}
  +
  +  {* (:one :local :two "surprise local!" :foo :bar :bar :hello :hash $hash) | $>locals ||}
  +
  +  {( {* (:one :first :two "surprise array!" :locals $locals)} {* (:one :second :two "surprise number also!" :locals $locals)} {* (:one :third :two "surprise me too!" :locals $locals)} ) | $>data ||}
  +
  +
  +  {$hash.one}
  +    hashly
  +
  +  // replacement with command parsing
  +  {$data.{"1"}.one}
  +    second
  +
  +  {$data.{1}.{$numbers.one}}
  +    second
  +
  +  // careful with numerical tests!
  +  {$data.1.one}
  +    second
  +
  +  {$data.#1.one}
  +    first
  +
  +  {$data.#-1.one}
  +    third
  +
  +  {$data.#12.one}
  +
  +  {$data.#-33.one}
  +
  +  // check iteration
  +  {$data.*.one}
  +    ["first","second","third"]
  +
  +  {$data.*.locals.hash.one}
  +    ["hashly","hashly","hashly"]
  +
  +  {$data.*.locals.foo}
  +    ["bar","bar","bar"]
  +
  +  {$data | eq $data.* | then :true else :false}
  +    true
  +  {$data.one | eq $data.*.one | then :true else :false}
  +    false
  +
  +  NOTE ON STARS
  +    $data and $data.* return exactly the same result, but $data.one and $data.*.one return different results. Why is that? 
  +    The * pathfind operator lifts the 'guts' of a list up one level, and exposes those items to future pathfinders. So while $data.one finds nothing -- because $data has no key of 'one' -- $data.*.one finds three things, because each item in $data has a key of 'one'.
  +    If however you merely return those lifted results without further operation then this is equivalent to simply removing the keys from the list -- and in $data's case it has no keys, so the two are equal.
  +    
  +    {(1 2) | __.*}
  +      [1,2]
  +    {* (:a 1 :b 2) | __.*}
  +      [1,2]
  +
  +  // check stars
  +  {$data | list count}
  +    3
  +
  +  {$data.* | list count}
  +    3
  +
  +  {$data.*.* | list count}
  +    9
  +
  +  {$data.*.*.* | list count}
  +    15
  +
  +  {$data.*.*.*.* | list count}
  +    9
  +
  +  {$data.one}
  +
  +  {$data.*.one}
  +    ["first","second","third"]
  +
  +  {$data.*.*.one}
  +    ["local","local","local"] 
  +
  +  {$data.*.*.*.one}
  +    ["hashly","hashly","hashly"]
  +
  +  {$data.*.*.*.*.one}
  +    []
  +
  +
  +  MORE NOTES ON STARS
  +    Since * exposes its inputs internals to the next operator, you can think of it as a map over the list with the rest of the operators as the block for that map, or the identity block if there are no further operators. This occasionally leads to counterintuitive results like the following, and generally means that * and #N don't play nicely together.
  +    
  +  Note that the positional pathfinder #N coerces scalar items into a singleton list, so #1 will continue returning a valid value. This differs from '0' -- the key-based pathfinder -- for unkeyed lists, as 0 does no coercion.
  +    {(1 2 3) | __.0}
  +      1
  +    {(1 2 3) | __.0.0}
  +    
  +    {(1 2 3) | __.#1}
  +      1
  +    {(1 2 3) | __.#1.#1}
  +      1
  +    {(1 2 3) | __.#1.#1.#1}
  +      1
  +    
  +    {$data.*.*.*.*}
  +      ["hashly","bashly","crashly","hashly","bashly","crashly","hashly","bashly","crashly"]
  +
  +  Remember, the star operator exposes the list internals to future operators in parallel, so #1 here eats nine scalar values.
  +    {$data.*.*.*.*.#1}
  +      ["hashly","bashly","crashly","hashly","bashly","crashly","hashly","bashly","crashly"]
  +    {$data.*.*.*.* | __.#1}
  +      hashly
  +      
  +  With star boxing you don't have to split the segments, but remember that the output is always wrapped in a list.
  +    {$data.{(("*" "*" "*" "*"))}.#1}
  +      ["hashly"]
  +      
  +    {$data.*.*.*.#1}
  +      ["local","surprise local!","bar","hello","hashly","local","surprise local!","bar","hello","hashly","local","surprise local!","bar","hello","hashly"] 
  +    {$data.*.*.* | __.#1}
  +      local
  +  
  +    {$data.*.*.#1}
  +      ["first","surprise array!","local","second","surprise number also!","local","third","surprise me too!","local"]
  +    {$data.*.* | __.#1}
  +      first
  +    
  +    {$data.*.#1}
  +      ["first","second","third"]
  +    {$data.* | __.#1}
  +      {"one":"first","two":"surprise array!","locals":{"one":"local","two":"surprise local!","foo":"bar","bar":"hello","hash":{"one":"hashly","two":"bashly","three":"crashly"}}} 
  +
  +
  +  STILL MORE NOTES ON STARS
  +    If you use a * or () pathfind operator, the result will ALWAYS be a list.
  +
  +    {$data.*.*.*.*.*}
  +      []
  +    {$data.*.*.*.*.*.#1}
  +      []
  +    {$data.foo.*}
  +      []
  +    {$data.*.one.foo}
  +      []
  +    {$data.*.one.#1.foo}
  +      []
  +
  +<h3>Tree climbing</h3>
  +
  +  {* (:name "Awesome John" :age :alpha) | $>a-john ||}
  +
  +  {* (:name "Awesome Bobs" :age :beta) | $>a-bobs ||}
  +
  +  {* (:name "Awesome Mary" :age :gamma) | $>a-mary ||}
  +
  +  {* (:name "Awesome Stev" :age :delta) | $>a-stev ||}
  +
  +  {($a-john $a-bobs $a-mary $a-stev) | $>awesome_people ||}
  +
  +  {* (:name "Cool John" :age :alpha) | $>c-john ||}
  +
  +  {* (:name "Cool Bobs" :age :beta) | $>c-bobs ||}
  +
  +  {* (:name "Cool Mary" :age :gamma) | $>c-mary ||}
  +
  +  {* (:name "Cool Stev" :age :delta) | $>c-stev ||}
  +
  +  {($c-john $c-bobs $c-mary $c-stev) | $>cool_people ||}
  +
  +  {* (:name "Neat John" :age :alpha) | $>n-john ||}
  +
  +  {* (:name "Neat Bobs" :age :beta) | $>n-bobs ||}
  +
  +  {* (:name "Neat Mary" :age :gamma) | $>n-mary ||}
  +
  +  {* (:name "Neat Stev" :age :delta) | $>n-stev ||}
  +
  +  {($n-john $n-bobs $n-mary $n-stev) | $>neat_people ||}
  +
  +  {( {* (:name "awesome test co" :employees $awesome_people :boss $a-john)} {* (:name "cool test co" :employees $cool_people :boss $c-john)} {* (:name "neat test co" :employees $neat_people :boss $n-john)} ) | $>companies ||}
  +
  +  NOW QUERY IT
  +  
  +  Find by position, then by property names:
  +    {$companies.#-2.boss.name}
  +      Cool John
  +
  +  All employees, grouped by employer
  +    {$companies.*.employees}
  +      [[{"name":"Awesome John","age":"alpha"},{"name":"Awesome Bobs","age":"beta"},{"name":"Awesome Mary","age":"gamma"},{"name":"Awesome Stev","age":"delta"}],[{"name":"Cool John","age":"alpha"},{"name":"Cool Bobs","age":"beta"},{"name":"Cool Mary","age":"gamma"},{"name":"Cool Stev","age":"delta"}],[{"name":"Neat John","age":"alpha"},{"name":"Neat Bobs","age":"beta"},{"name":"Neat Mary","age":"gamma"},{"name":"Neat Stev","age":"delta"}]]
  +
  +  A flat list of all employees
  +    {$companies.*.employees.*}
  +      [{"name":"Awesome John","age":"alpha"},{"name":"Awesome Bobs","age":"beta"},{"name":"Awesome Mary","age":"gamma"},{"name":"Awesome Stev","age":"delta"},{"name":"Cool John","age":"alpha"},{"name":"Cool Bobs","age":"beta"},{"name":"Cool Mary","age":"gamma"},{"name":"Cool Stev","age":"delta"},{"name":"Neat John","age":"alpha"},{"name":"Neat Bobs","age":"beta"},{"name":"Neat Mary","age":"gamma"},{"name":"Neat Stev","age":"delta"}]
  +
  +  All employee names
  +    {$companies.*.employees.*.name}
  +      ["Awesome John","Awesome Bobs","Awesome Mary","Awesome Stev","Cool John","Cool Bobs","Cool Mary","Cool Stev","Neat John","Neat Bobs","Neat Mary","Neat Stev"]
  +
  +  All employee names of the second company
  +    {$companies.#2.employees.*.name}
  +      ["Cool John","Cool Bobs","Cool Mary","Cool Stev"]
  +  
  +  Second employee name of each company
  +    {$companies.*.employees.#2.name}
  +      ["Awesome Bobs","Cool Bobs","Neat Bobs"]
  +  
  +  Second employee name over all
  +    {$companies.*.employees.* | __.#2.name}
  +      Awesome Bobs
  +
  +  Star boxing gives us the second name with a single {list peek} call, but remember that it always returns a list.
  +    {$companies.{(("*" "employees" "*"))}.#2.name}
  +      ["Awesome Bobs"]
  +
  +  Without star boxing it looks in all the wrong places
  +    {$companies.*.employees.*.#2.name}
  +      []
  +    {$companies.*.employees.*.name.#2}
  +      []
  +
  +<h3>Dot sugar</h3>
  +  Pairs of commands: the dot-form and the list peek form, side by side.
  +  
  +    {(1 2 3) | __.#2}
  +      2
  +    {(1 2 3) | list peek path "#2"}
  +      2
  +
  +    {( (1 2) (3 4) ) | __.#2.#1}
  +      3
  +    {( (1 2) (3 4) ) | list peek path ("#2" "#1")}
  +      3
  +
  +    {( (1 2) (3 4) ) | __.{("#2" "#1")}.#2}
  +      [4,2]
  +    {( (1 2) (3 4) ) | list peek path ( ("#2" "#1") "#2" )}
  +      [4,2]
  +
  +    {( (1 2) (3 4) ) | __.{("#2" "#1")}.{(1 0)} }
  +      [4,3,2,1]
  +    {( (1 2) (3 4) ) | list peek path ( ("#2" "#1") (1 0) )}
  +      [4,3,2,1]
  +      
  +    {( (1 2) (3 4) ) | __.{("#2" "#1")}.{(((1 0)))} }
  +      [[4,3],[2,1]]
  +    {( (1 2) (3 4) ) | list peek path ( ("#2" "#1") (((1 0))) )}
  +      [[4,3],[2,1]]
  +
  +    {( (1 2) (3 4) ) | __.*.{(1 0)} }
  +      [2,1,4,3]
  +    {( (1 2) (3 4) ) | list peek path ( "*" (1 0) )}
  +      [2,1,4,3]
  +
  +    {( (1 2) (3 4) ) | __.*.{(((1 0)))} }
  +      [[2,1],[4,3]] 
  +    {( (1 2) (3 4) ) | list peek path ( "*" (((1 0))) )}
  +      [[2,1],[4,3]] 
  +      
  +<h3>Series and parallel</h3>
  +
  +  peek in series: first take the second element, then take its first element
  +    {( (1 2) (3 4) ) | list peek path ( 1 0 )} 
  +      3
  +      
  +  peek in parallel: take the second element, and the first element, and stage them for further peeking
  +    {( (1 2) (3 4) ) | list peek path ( (1 0) )} 
  +      [[3,4],[1,2]]
  +      
  +  now we've taken the second element of each of the staged items
  +    {( (1 2) (3 4) ) | list peek path ( (1 0) 1 )} 
  +      [4,2]
  +
  +  we've learned:
  +  -- the first list is processed in series
  +  -- sublists are processed in parallel
  +  
  +  now we'll see that those alternate: a sub-sub-list is processed in series.
  +  
  +  this takes the first element of the second element, but does it in parallel -- hence the list wrapping
  +    {( (1 2) (3 4) ) | list peek path ( ((1 0)) )}
  +      [3]
  +
  +  same, but with a second serial pathway inside the parallel one
  +    {( (1 2) (3 4) ) | list peek path ( ((1 0) (1 1)) )}
  +      [3,4]
  +    
  +  parallel + series + parallel -- each parallel layer adds another wrapper list 
  +    {( (1 2) (3 4) ) | list peek path ( (((1 0))) )}
  +      [[[3,4],[1,2]]]
  +  
  +  take the second element of our list of lists
  +    {( (1 2) (3 4) ) | list peek path ( (((1 0))) 1 )}
  +      [[1,2]]
  +      
  +  why is it [[1,2]] instead of [1,2]? 
  +  once we've gone parallel (or used "*"), the results are always wrapped in a list regardless of the number of results. 
  +  if we stay serial the whole time any matching elements are returned as-is.
  +  
  +  now we take the first element of the above
  +    {( (1 2) (3 4) ) | list peek path ( (((1 0))) 1 0 )}
  +      [1]
  +  
  +  the second parallel pathway here is fed our forest, and reverses the reversed order -- restoring our original input
  +    {( (1 2) (3 4) ) | list peek path ( (((1 0))) (1 0) )}
  +      [[1,2],[3,4]]
  +  
  +  without the extra parallel wrapping the second pathway operates on the list elements instead of the lists
  +    {( (1 2) (3 4) ) | list peek path ( (1 0) (1 0) )}
  +      [4,3,2,1]
  +  
  +  this time the second pathway operates serially -- same result as without the dressing
  +    {( (1 2) (3 4) ) | list peek path ( (((1 0))) ((1 0)) )}
  +      [1]
  +
  +  remember that the second pathway is seeing the lists in reversed order
  +    {( (1 2) (3 4) ) | list peek path ( (((1 0))) ((1 0) (0 1)) )}
  +      [1,4]
  +      
  +  same double reversal as above, but with an extra layer of wrapping
  +    {( (1 2) (3 4) ) | list peek path ( (((1 0))) (((1 0))) )}
  +      [[[1,2],[3,4]]]
  +  
  +  the star unwraps staged items and feeds them to the next pathway
  +    {( (1 2) (3 4) ) | list peek path ( (((1 0))) "*" 1 )}
  +      [4,2]
  +
  +  which is equivalent to this, for the two element case
  +    {( (1 2) (3 4) ) | list peek path ( (((1 0))) (0 1) 1 )}
  +      [4,2]
  +      
  +  parallel consumption post star
  +    {( (1 2) (3 4) ) | list peek path ( (((1 0))) "*" (1 0) )}
  +      [4,3,2,1]
  +
  +  note the equivalence -- the star unwrapifies our initial double-layering
  +    {( (1 2) (3 4) ) | list peek path ( (1 0) (1 0) )}
  +      [4,3,2,1]
  +      
  +  which here allows us to reverse the list order, then the element order
  +    {( (1 2) (3 4) ) | list peek path ( (((1 0))) "*" (((1 0))) )}
  +      [[4,3],[2,1]]
  +  
  +  and the simpler equivalent
  +    {( (1 2) (3 4) ) | list peek path ( (1 0) (((1 0))) )}
  +      [[4,3],[2,1]]
  +
  +
  +<h2>In Depth: Poke</h2>
  +  Poking is a lot like peeking, except it sets a value instead of reading it and fills any gaps it encounters with empty lists.
  +
  +  no path is like push
  +    {(1 2 3) | list poke value 999}
  +      [1,2,3,999]
  +
  +  three ways to push a new value on a list
  +    {(1 2 3 4) | $>ints}
  +      [1,2,3,4]
  +    {5 | $>ints.{$ints | count}}  {// BUG //}
  +      5
  +    {$ints | poke 6}
  +      [1,2,3,4,5,6]
  +    {$ints | union 6}
  +      [1,2,3,4,5,6]
  +
  +  by key:
  +    {(1 2 3) | list poke path (1) value 999}
  +      [1,999,3]
  +    {(1 2 3) | list poke path (1 :a) value 999}
  +      [1,{"a":999},3]
  +    {* (:a 1 :b 2 :c 3) | list poke path (:d) value 999}
  +      {"a":1,"b":2,"c":3,"d":999} 
  +    {* (:a (2 1) :b (3 4) :c (4 5)) | list poke path (:b 1) value 999}
  +      {"a":[2,1],"b":[3,999],"c":[4,5]} 
  +    {* (:a (2 1) :b (3 4) :c (4 5)) | list poke path (:b 1 :d) value 999}
  +      {"a":[2,1],"b":[3,{"d":999}],"c":[4,5]} 
  +    {* (:a (2 1) :b (3 4) :c (4 5)) | list poke path (:b 1 :d :e) value 999}
  +      {"a":[2,1],"b":[3,{"d":{"e":999}}],"c":[4,5]} 
  +    
  +    when you poke by key to a non-existent key in an unkeyed list, it converts it to a keyed list. (BUG)
  +      {(1 2 3) | list poke path (:a) value 999}
  +        {"0":1,"1":2,"2":3,"a":999}
  +
  +  by position:
  +    {(1 2 3) | list poke path ("#2") value 999}
  +      [1,999,3]
  +    {* (:a (2 1) :b (3 4) :c (4 5)) | list poke path ("#2") value 999}
  +      {"a":[2,1],"b":999,"c":[4,5]}
  +    {* (:a (2 1) :b (3 4) :c (4 5)) | list poke path ("#2" "#2") value 999}
  +      {"a":[2,1],"b":[3,999],"c":[4,5]}
  +  
  +    the positional operator fills gaps with empty lists
  +      {() | list poke path ("#2") value 999}
  +        [[],999]
  +      {() | list poke path ("#-2") value 999}
  +        [999,[]]
  +      {() | list poke path ("#-2" "#3") value 999}
  +        [[[],[],999],[]] 
  +      {() | list poke path ("#-2" "#3" "#-4") value 999}
  +        [[[],[],[999,[],[],[]]],[]]
  +
  +    it mixes well with keyed lists, as long as enough elements exist. 
  +      {* (:a (2 1) :b (3 4) :c (4 5)) | list poke path ("#1" "#4") value 999}
  +        {"a":[2,1,[],999],"b":[3,4],"c":[4,5]} 
  +      {* (:a (2 1) :b (3 4) :c (4 5)) | list poke path ("#1" "#-6") value 999}
  +        {"a":[999,[],[],[],2,1],"b":[3,4],"c":[4,5]}        
  +      {* (:a {* (:aa 1 :ab 2)} :b {* (:ba 1 :bb 2)} :c {* (:ca 1 :cb 2)}) | list poke path ("#2" "#2") value 999}
  +        {"a":{"aa":1,"ab":2},"b":{"ba":1,"bb":999},"c":{"ca":1,"cb":2}} 
  +    
  +    but if there are gaps in your keyed list the results might be unexpected -- the generated keys are consecutive integers (offset by one million to avoid common collisions). 
  +    this behavior is likely to change; please don't rely on generated keys.
  +      {* (:a 1 :b 2 :c 3) | list poke path ("#5") value 999}
  +        {"1000000":[],"1000001":999,"a":1,"b":2,"c":3}
  +      {* (:a 1 :b 2 :c 3) | list poke path ("#5") value 999 | sort}
  +        [[],1,2,3,999]
  +      
  +      
  +  by star:
  +    
  +    {(2 3 4) | list poke path "*" value 999}
  +      [999,999,999]
  +    {((2 1) (3 4) (4 5)) | list poke path "*" value 999}
  +      [999,999,999]
  +    {((2 1) (3 4) (4 5)) | list poke path ("*" "#2") value 999}
  +      [[2,999],[3,999],[4,999]]
  +    {((2 1) (3 4) (4 5)) | list poke path ("#2" "*") value 999}
  +      [[2,1],[999,999],[4,5]]
  +    {((2 1) (3 4) (4 5)) | list poke path ("*" "*") value 999}
  +      [[999,999],[999,999],[999,999]]
  +      
  +    stars generate a new empty list for each missing (or scalar) level. (BUG)
  +      {() | list poke path ("*") value 999}
  +        []
  +      {() | list poke path ("*" "*") value 999}
  +        [[]]
  +      {(1 2 3) | list poke path ("*" "*") value 999}
  +        [[],[],[]]
  +      {(1 2 3) | list poke path ("*" "*" "*") value 999}
  +        [[[]],[[]],[[]]]
  +      {(1 2 3) | list poke path ("*" "*" "#2") value 999}
  +        [[[],999],[[],999],[[],999]]
  +        
  +    
  +  by list:
  +    
  +    {* (:a 1 :b 2 :c 3) | list poke path ( (:a :b) ) value 999}
  +      {"a":999,"b":999,"c":3}
  +    {* (:a 1 :b 2 :c 3) | list poke path ( (:d :e) ) value 999}
  +      {"a":1,"b":2,"c":3,"d":999,"e":999}
  +    {* (:a 1 :b 2 :c 3) | list poke path ( ("#1" "#3") ) value 999}
  +      {"a":999,"b":2,"c":999}
  +    {((2 1) (3 4) (4 5)) | list poke path ("*" ("#2" "#4") ) value 999}
  +      [[2,999,[],999],[3,999,[],999],[4,999,[],999]]
  +      
  +    generating a new list
  +      {* (:a 1 :b 2 :c 3) | list poke path ( "#2" ("#2" "#6" "#4") ) value 999}
  +        {"a":1,"b":[[],999,[],999,[],999],"c":3}
  +      
  +    generating a new list (BUG)
  +      {* (:a 1 :b 2 :c 3) | list poke path ( :b ("#2" "#6" "#4") ) value 999}
  +        {"a":1,"b":[[],999,[],999,[],999],"c":3}
  +      
  +    generating a new keyed list (BUG)
  +      {* (:a 1 :b 2 :c 3) | list poke path ( "#2" (:d :e) ) value 999}
  +        {"a":1,"b":{"d":999,"e":999},"c":3}
  +
  +    double list all the way (BUG)
  +      {((2 1) (3 4) (4 5)) | list poke path ( ("#1" "#3") ("#2" "#4") ) value 999}
  +        [[2,999,[],999],[3,4],[4,999,[],999]]
  +
  +
   
   <!-- Aliases and bindings
   
  
positive.code: -->
  
  
  MAGIC PIPE TESTS
  
    The magic pipe has two uses: to explicitly connect two segments, and to access the Process's input value
  
    Case 1: explicit connection. Each of these also has an implicit connection, but only the first example uses it because the others have no additional param space (add only takes two params).
      {21 | add __}
        42
      {21 | add 21 to __}
        42
      {21 | add __ to 21}
        42
      {21 | add __ to __}
        42
  
    Case 1a: blocking implicit connection. The double pipe doesn't pass values implicitly, but you can still use the magic pipe to explicitly link them. Useful for commands that have multiple parameters.
      {42 || add __}
        42
      {21 || add 21 to __}
        42
  
    Case 1b: carry along. You can use a pipe to carry the value through segments.
      {42 | __}
        42
      {42 | __ | __}
        42
      
    Case 1c: duplication. You can use pipes in lists to duplicate the previous value
      {42 | (__)}
        [42]
      {42 | (__ __)}
        [42,42]
      {42 | (:x __ __)}
        ["x",42,42]
      {42 | (__ :x __)}
        [42,"x",42]
      {42 | (__ __ :x)}
        [42,42,"x"]
      
      {21 | add (__)}
        [42]
      {21 | add (__ __)}
        [42,42]
      {21 | add (-1 __ __)}
        [20,42,42]
      {21 | add (__ -1 __)}
        [42,20,42]
      {21 | add (__ __ -1)}
        [42,42,20]
  
  
    Rethinking Case 2. Having two different meanings of __ is probably overly complicated. I still like the idea of imagining the process input peeking in through the beginning of the pipeline, and I'd like to use that some day for things like {(1 2 3) | map "{add 1}"} but if we're going to be explicit about it why not use a different symbol? 
    [well, for one reason, some aliases have pipes in them: {(1 0 3) | map "{then :ham else :foo}"} -> (:ham :foo :ham) via front-pipes]
    maybe... maybe having ({__} {__}) freak out and do stupid things is reasonable, in the same way that other languages give syntax errors for stupid things. it's hard making a language with no real errors!
    and it's not like that construct is really that stupid -- if you really want the process input maybe that should give it to you? or... no, it's really stupid. it's inside another pipeline, so it can't be the outermost thing in the process. it should probably just return nothing, or "". Probably ("{__}" "{__}") -> ("" "") also. 
    BUT, {(1 2 3) | map "{__}"} -> (1 2 3). We really need an identity block. It's just that in the above it's getting the identity of nothing. 
    
  
  
  
    Case 2: access to process input. These are simple cases involving a single pipeline. Notice that the magic pipe must be in the first segment to access the process's input value. Magic pipes in later segments will reference the previous segment value.
    
      ----- thoughts on this:
      - if we made 'process input' a different symbol we wouldn't have embedded pipeline reference issues 
        - referencing the previous segment from inside a list is an important case
        - is it the only case??
      - starting a pipeline with __ is beautifully simple
        - it clearly indicates the intention of pulling in outside input
        - it demonstrates the linear nature of a pipeline: one thing in, one thing out
        - we lose this if we allow references inside a pipeline (oh we're doing that already oh dear)
      - the block case with multiple pipelines each referencing input is important, because
        - we want those to be able to run in parallel
        - a given pipeline should work the same regardless of context
        - so we can't just rely on 'first use' of __ and alias it after
      
      so it sounds like a different symbol is in order to refer universally to the input.
      OR we do something fiddly like {__} means input if it's outermost but embedded it never does (yuck).
      //   {__ | add 1}
      //   {_in | add 1}
      //   {*in | add 1}
      //   {___ | add 1}
      
      er... if it's inside a string, it maps to '*in'.
      if it's inside a list, it maps to prevval.
      is it that simple?
      // this is a pipe
      // ceci n'est pas une pipe
      
      
      
    
      {(1 2 3) | map block "{__ | add 4}"}
        [5,6,7]
      {(1 2 3) | map block "{add __ to 4}"}
        [5,6,7]
      {(1 2 3) | map block "{add __ to __}"}
        [2,4,6]
      {(1 2 3) | map block "{__}"}
        [1,2,3]
      {(1 2 3) | map block "{__ | __}"}
        [1,2,3]
      {(1 2 3) | map block "{__ | __ | add 1}"}
        [2,3,4]
      {(1 2 3) | map block "{__ | add 1 | __ | add 1}"}
        [3,4,5]
    
    Case 2a: block-level access. Multiple pipelines in a block can each access the process input.
      {begin foo | each data (1 2 3)} {__ | add 3} x {__ | add 7} ::{end foo}
        4 x 8 :: 5 x 9 :: 6 x 10 ::
      {begin foo | each data (1 2 3)} {add 3 to __} x {add __ to 7} ::{end foo}
        4 x 8 :: 5 x 9 :: 6 x 10 ::
    
    You can reframe the above like this:
      {(1 2 3) | each block "{__ | (" " {__in | add 3} " x " {__in | add 7} " ::") | join}"}
        4 x 8 :: 5 x 9 :: 6 x 10 ::
    
    Notes:
      To connect to the process input you must explicitly add the magic pipe to the first segment:
        {(1 2 3) | map block "{__ | add to 4}"}
          [5,6,7]
        {(1 2 3) | map block "{add to 4}" // bad}
          [4,4,4]
        {(1 2 3) | map block "{__ | add 4}"}
          [5,6,7]
        {(1 2 3) | map block "{add 4}" // bad}
          [4,4,4]
      
      
  ////    //The first segment of an inline pipeline also grab the process input instead of the previous segment value -- this is almost certainly not what you want. 
  ////THINK: how does this square off with __.foo? that essentially becomes {__ | list peek path (:foo)} and could be a param value or in a list. so {1 | ({__} {__})} should be (1 1) by that logic. what was the issue with that?
  ////If, while using a pipeline as a param value, you want access to the previous pipe segment's value, then you should either refactor the pipeline to do the processing beforehand (as above), or assign the value to a pipeline var.
  
  
      NEW RULES!
      - "{__}" links to process input
      - {__} links to previous value
      so: if it's in a string, it's input.
          if it's in a list or param value it's previous value.
  
  
        {20 | add {__ | add 2}}
          42
        {20 | add {__ | add 2} to __}
          42
      
        {21 | join (__ " " __) on ""}
          21 21
        {21 | ( {__ | add 1} " " {__ | add 2} ) | join}
          22 23
        {21 | ( {add 1 to __} " " {add __ to 2} ) | join}
          22 23
        {21 | >a | ( {_a | add 1} " " {_a | add 2} ) | join}
          22 23
    
        {40 | add {__} to 2}
          42
        {21 | add {__} to __}
          42
        {21 | add __ to {__}}
          42
        {21 | add {__} to {__}}
          42
        {20 | ( {__} 2 __ ) | add}
          42
        {20 | ( __ 2 {__} ) | add}
          42
        {20 | ( {__} 2 {__} ) | add}
          42
      
      Double pipes are also used to squelch output from a pipeline:
        {42 ||}
          
        {(1 2 3) | map block "{__ | add 1 ||}"}
          ["","",""]
    
    
    
    
  <h2>In Depth: Peek</h2>
  
    This is a section all about how my list searching got flipped turned upside down. It includes the majority of the peek tests.
  
    {* (:one :one :two :two :three :three) | $>numbers ||}
  
    {* (:one :hashly :two :bashly :three :crashly) | $>hash ||}
  
    {* (:one :local :two "surprise local!" :foo :bar :bar :hello :hash $hash) | $>locals ||}
  
    {( {* (:one :first :two "surprise array!" :locals $locals)} {* (:one :second :two "surprise number also!" :locals $locals)} {* (:one :third :two "surprise me too!" :locals $locals)} ) | $>data ||}
  
  
    {$hash.one}
      hashly
  
    // replacement with command parsing
    {$data.{"1"}.one}
      second
  
    {$data.{1}.{$numbers.one}}
      second
  
    // careful with numerical tests!
    {$data.1.one}
      second
  
    {$data.#1.one}
      first
  
    {$data.#-1.one}
      third
  
    {$data.#12.one}
  
    {$data.#-33.one}
  
    // check iteration
    {$data.*.one}
      ["first","second","third"]
  
    {$data.*.locals.hash.one}
      ["hashly","hashly","hashly"]
  
    {$data.*.locals.foo}
      ["bar","bar","bar"]
  
    {$data | eq $data.* | then :true else :false}
      true
    {$data.one | eq $data.*.one | then :true else :false}
      false
  
    NOTE ON STARS
      $data and $data.* return exactly the same result, but $data.one and $data.*.one return different results. Why is that? 
      The * pathfind operator lifts the 'guts' of a list up one level, and exposes those items to future pathfinders. So while $data.one finds nothing -- because $data has no key of 'one' -- $data.*.one finds three things, because each item in $data has a key of 'one'.
      If however you merely return those lifted results without further operation then this is equivalent to simply removing the keys from the list -- and in $data's case it has no keys, so the two are equal.
      
      {(1 2) | __.*}
        [1,2]
      {* (:a 1 :b 2) | __.*}
        [1,2]
  
    // check stars
    {$data | list count}
      3
  
    {$data.* | list count}
      3
  
    {$data.*.* | list count}
      9
  
    {$data.*.*.* | list count}
      15
  
    {$data.*.*.*.* | list count}
      9
  
    {$data.one}
  
    {$data.*.one}
      ["first","second","third"]
  
    {$data.*.*.one}
      ["local","local","local"] 
  
    {$data.*.*.*.one}
      ["hashly","hashly","hashly"]
  
    {$data.*.*.*.*.one}
      []
  
  
    MORE NOTES ON STARS
      Since * exposes its inputs internals to the next operator, you can think of it as a map over the list with the rest of the operators as the block for that map, or the identity block if there are no further operators. This occasionally leads to counterintuitive results like the following, and generally means that * and #N don't play nicely together.
      
    Note that the positional pathfinder #N coerces scalar items into a singleton list, so #1 will continue returning a valid value. This differs from '0' -- the key-based pathfinder -- for unkeyed lists, as 0 does no coercion.
      {(1 2 3) | __.0}
        1
      {(1 2 3) | __.0.0}
      
      {(1 2 3) | __.#1}
        1
      {(1 2 3) | __.#1.#1}
        1
      {(1 2 3) | __.#1.#1.#1}
        1
      
      {$data.*.*.*.*}
        ["hashly","bashly","crashly","hashly","bashly","crashly","hashly","bashly","crashly"]
  
    Remember, the star operator exposes the list internals to future operators in parallel, so #1 here eats nine scalar values.
      {$data.*.*.*.*.#1}
        ["hashly","bashly","crashly","hashly","bashly","crashly","hashly","bashly","crashly"]
      {$data.*.*.*.* | __.#1}
        hashly
        
    With star boxing you don't have to split the segments, but remember that the output is always wrapped in a list.
      {$data.{(("*" "*" "*" "*"))}.#1}
        ["hashly"]
        
      {$data.*.*.*.#1}
        ["local","surprise local!","bar","hello","hashly","local","surprise local!","bar","hello","hashly","local","surprise local!","bar","hello","hashly"] 
      {$data.*.*.* | __.#1}
        local
    
      {$data.*.*.#1}
        ["first","surprise array!","local","second","surprise number also!","local","third","surprise me too!","local"]
      {$data.*.* | __.#1}
        first
      
      {$data.*.#1}
        ["first","second","third"]
      {$data.* | __.#1}
        {"one":"first","two":"surprise array!","locals":{"one":"local","two":"surprise local!","foo":"bar","bar":"hello","hash":{"one":"hashly","two":"bashly","three":"crashly"}}} 
  
  
    STILL MORE NOTES ON STARS
      If you use a * or () pathfind operator, the result will ALWAYS be a list.
  
      {$data.*.*.*.*.*}
        []
      {$data.*.*.*.*.*.#1}
        []
      {$data.foo.*}
        []
      {$data.*.one.foo}
        []
      {$data.*.one.#1.foo}
        []
  
  <h3>TREE SHAPING</h3>
  
    {* (:name "Awesome John" :age :alpha) | $>a-john ||}
  
    {* (:name "Awesome Bobs" :age :beta) | $>a-bobs ||}
  
    {* (:name "Awesome Mary" :age :gamma) | $>a-mary ||}
  
    {* (:name "Awesome Stev" :age :delta) | $>a-stev ||}
  
    {($a-john $a-bobs $a-mary $a-stev) | $>awesome_people ||}
  
    {* (:name "Cool John" :age :alpha) | $>c-john ||}
  
    {* (:name "Cool Bobs" :age :beta) | $>c-bobs ||}
  
    {* (:name "Cool Mary" :age :gamma) | $>c-mary ||}
  
    {* (:name "Cool Stev" :age :delta) | $>c-stev ||}
  
    {($c-john $c-bobs $c-mary $c-stev) | $>cool_people ||}
  
    {* (:name "Neat John" :age :alpha) | $>n-john ||}
  
    {* (:name "Neat Bobs" :age :beta) | $>n-bobs ||}
  
    {* (:name "Neat Mary" :age :gamma) | $>n-mary ||}
  
    {* (:name "Neat Stev" :age :delta) | $>n-stev ||}
  
    {($n-john $n-bobs $n-mary $n-stev) | $>neat_people ||}
  
    {( {* (:name "awesome test co" :employees $awesome_people :boss $a-john)} {* (:name "cool test co" :employees $cool_people :boss $c-john)} {* (:name "neat test co" :employees $neat_people :boss $n-john)} ) | $>companies ||}
  
    NOW QUERY IT
    
    Find by position, then by property names:
      {$companies.#-2.boss.name}
        Cool John
  
    All employees, grouped by employer
      {$companies.*.employees}
        [[{"name":"Awesome John","age":"alpha"},{"name":"Awesome Bobs","age":"beta"},{"name":"Awesome Mary","age":"gamma"},{"name":"Awesome Stev","age":"delta"}],[{"name":"Cool John","age":"alpha"},{"name":"Cool Bobs","age":"beta"},{"name":"Cool Mary","age":"gamma"},{"name":"Cool Stev","age":"delta"}],[{"name":"Neat John","age":"alpha"},{"name":"Neat Bobs","age":"beta"},{"name":"Neat Mary","age":"gamma"},{"name":"Neat Stev","age":"delta"}]]
  
    A flat list of all employees
      {$companies.*.employees.*}
        [{"name":"Awesome John","age":"alpha"},{"name":"Awesome Bobs","age":"beta"},{"name":"Awesome Mary","age":"gamma"},{"name":"Awesome Stev","age":"delta"},{"name":"Cool John","age":"alpha"},{"name":"Cool Bobs","age":"beta"},{"name":"Cool Mary","age":"gamma"},{"name":"Cool Stev","age":"delta"},{"name":"Neat John","age":"alpha"},{"name":"Neat Bobs","age":"beta"},{"name":"Neat Mary","age":"gamma"},{"name":"Neat Stev","age":"delta"}]
  
    All employee names
      {$companies.*.employees.*.name}
        ["Awesome John","Awesome Bobs","Awesome Mary","Awesome Stev","Cool John","Cool Bobs","Cool Mary","Cool Stev","Neat John","Neat Bobs","Neat Mary","Neat Stev"]
  
    All employee names of the second company
      {$companies.#2.employees.*.name}
        ["Cool John","Cool Bobs","Cool Mary","Cool Stev"]
    
    Second employee name of each company
      {$companies.*.employees.#2.name}
        ["Awesome Bobs","Cool Bobs","Neat Bobs"]
    
    Second employee name over all
      {$companies.*.employees.* | __.#2.name}
        Awesome Bobs
  
    Star boxing gives us the second name with a single {list peek} call, but remember that it always returns a list.
      {$companies.{(("*" "employees" "*"))}.#2.name}
        ["Awesome Bobs"]
  
    Without star boxing it looks in all the wrong places
      {$companies.*.employees.*.#2.name}
        []
      {$companies.*.employees.*.name.#2}
        []
  
  <h3>Dot sugar</h3>
    Pairs of commands: the dot-form and the list peek form, side by side.
    
      {(1 2 3) | __.#2}
        2
      {(1 2 3) | list peek path "#2"}
        2
  
      {( (1 2) (3 4) ) | __.#2.#1}
        3
      {( (1 2) (3 4) ) | list peek path ("#2" "#1")}
        3
  
      {( (1 2) (3 4) ) | __.{("#2" "#1")}.#2}
        [4,2]
      {( (1 2) (3 4) ) | list peek path ( ("#2" "#1") "#2" )}
        [4,2]
  
      {( (1 2) (3 4) ) | __.{("#2" "#1")}.{(1 0)} }
        [4,3,2,1]
      {( (1 2) (3 4) ) | list peek path ( ("#2" "#1") (1 0) )}
        [4,3,2,1]
        
      {( (1 2) (3 4) ) | __.{("#2" "#1")}.{(((1 0)))} }
        [[4,3],[2,1]]
      {( (1 2) (3 4) ) | list peek path ( ("#2" "#1") (((1 0))) )}
        [[4,3],[2,1]]
  
      {( (1 2) (3 4) ) | __.*.{(1 0)} }
        [2,1,4,3]
      {( (1 2) (3 4) ) | list peek path ( "*" (1 0) )}
        [2,1,4,3]
  
      {( (1 2) (3 4) ) | __.*.{(((1 0)))} }
        [[2,1],[4,3]] 
      {( (1 2) (3 4) ) | list peek path ( "*" (((1 0))) )}
        [[2,1],[4,3]] 
        
  <h3>Series and parallel</h3>
  
    peek in series: first take the second element, then take its first element
      {( (1 2) (3 4) ) | list peek path ( 1 0 )} 
        3
        
    peek in parallel: take the second element, and the first element, and stage them for further peeking
      {( (1 2) (3 4) ) | list peek path ( (1 0) )} 
        [[3,4],[1,2]]
        
    now we've taken the second element of each of the staged items
      {( (1 2) (3 4) ) | list peek path ( (1 0) 1 )} 
        [4,2]
  
    we've learned:
    -- the first list is processed in series
    -- sublists are processed in parallel
    
    now we'll see that those alternate: a sub-sub-list is processed in series.
    
    this takes the first element of the second element, but does it in parallel -- hence the list wrapping
      {( (1 2) (3 4) ) | list peek path ( ((1 0)) )}
        [3]
  
    same, but with a second serial pathway inside the parallel one
      {( (1 2) (3 4) ) | list peek path ( ((1 0) (1 1)) )}
        [3,4]
      
    parallel + series + parallel -- each parallel layer adds another wrapper list 
      {( (1 2) (3 4) ) | list peek path ( (((1 0))) )}
        [[[3,4],[1,2]]]
    
    take the second element of our list of lists
      {( (1 2) (3 4) ) | list peek path ( (((1 0))) 1 )}
        [[1,2]]
        
    why is it [[1,2]] instead of [1,2]? 
    once we've gone parallel (or used "*"), the results are always wrapped in a list regardless of the number of results. 
    if we stay serial the whole time any matching elements are returned as-is.
    
    now we take the first element of the above
      {( (1 2) (3 4) ) | list peek path ( (((1 0))) 1 0 )}
        [1]
    
    the second parallel pathway here is fed our forest, and reverses the reversed order -- restoring our original input
      {( (1 2) (3 4) ) | list peek path ( (((1 0))) (1 0) )}
        [[1,2],[3,4]]
    
    without the extra parallel wrapping the second pathway operates on the list elements instead of the lists
      {( (1 2) (3 4) ) | list peek path ( (1 0) (1 0) )}
        [4,3,2,1]
    
    this time the second pathway operates serially -- same result as without the dressing
      {( (1 2) (3 4) ) | list peek path ( (((1 0))) ((1 0)) )}
        [1]
  
    remember that the second pathway is seeing the lists in reversed order
      {( (1 2) (3 4) ) | list peek path ( (((1 0))) ((1 0) (0 1)) )}
        [1,4]
        
    same double reversal as above, but with an extra layer of wrapping
      {( (1 2) (3 4) ) | list peek path ( (((1 0))) (((1 0))) )}
        [[[1,2],[3,4]]]
    
    the star unwraps staged items and feeds them to the next pathway
      {( (1 2) (3 4) ) | list peek path ( (((1 0))) "*" 1 )}
        [4,2]
  
    which is equivalent to this, for the two element case
      {( (1 2) (3 4) ) | list peek path ( (((1 0))) (0 1) 1 )}
        [4,2]
        
    parallel consumption post star
      {( (1 2) (3 4) ) | list peek path ( (((1 0))) "*" (1 0) )}
        [4,3,2,1]
  
    note the equivalence -- the star unwrapifies our initial double-layering
      {( (1 2) (3 4) ) | list peek path ( (1 0) (1 0) )}
        [4,3,2,1]
        
    which here allows us to reverse the list order, then the element order
      {( (1 2) (3 4) ) | list peek path ( (((1 0))) "*" (((1 0))) )}
        [[4,3],[2,1]]
    
    and the simpler equivalent
      {( (1 2) (3 4) ) | list peek path ( (1 0) (((1 0))) )}
        [[4,3],[2,1]]
  
  
  <h2>In Depth: Poke</h2>
    Poking is a lot like peeking, except it sets a value instead of reading it and fills any gaps it encounters with empty lists.
  
    no path is like push
      {(1 2 3) | list poke value 999}
        [1,2,3,999]
  
    three ways to push a new value on a list
      {(1 2 3 4) | $>ints}
        [1,2,3,4]
      {5 | $>ints.{$ints | count}}  {// BUG //}
        5
      {$ints | poke 6}
        [1,2,3,4,5,6]
      {$ints | union 6}
        [1,2,3,4,5,6]
  
    by key:
      {(1 2 3) | list poke path (1) value 999}
        [1,999,3]
      {(1 2 3) | list poke path (1 :a) value 999}
        [1,{"a":999},3]
      {* (:a 1 :b 2 :c 3) | list poke path (:d) value 999}
        {"a":1,"b":2,"c":3,"d":999} 
      {* (:a (2 1) :b (3 4) :c (4 5)) | list poke path (:b 1) value 999}
        {"a":[2,1],"b":[3,999],"c":[4,5]} 
      {* (:a (2 1) :b (3 4) :c (4 5)) | list poke path (:b 1 :d) value 999}
        {"a":[2,1],"b":[3,{"d":999}],"c":[4,5]} 
      {* (:a (2 1) :b (3 4) :c (4 5)) | list poke path (:b 1 :d :e) value 999}
        {"a":[2,1],"b":[3,{"d":{"e":999}}],"c":[4,5]} 
      
      when you poke by key to a non-existent key in an unkeyed list, it converts it to a keyed list. (BUG)
        {(1 2 3) | list poke path (:a) value 999}
          {"0":1,"1":2,"2":3,"a":999}
  
    by position:
      {(1 2 3) | list poke path ("#2") value 999}
        [1,999,3]
      {* (:a (2 1) :b (3 4) :c (4 5)) | list poke path ("#2") value 999}
        {"a":[2,1],"b":999,"c":[4,5]}
      {* (:a (2 1) :b (3 4) :c (4 5)) | list poke path ("#2" "#2") value 999}
        {"a":[2,1],"b":[3,999],"c":[4,5]}
    
      the positional operator fills gaps with empty lists
        {() | list poke path ("#2") value 999}
          [[],999]
        {() | list poke path ("#-2") value 999}
          [999,[]]
        {() | list poke path ("#-2" "#3") value 999}
          [[[],[],999],[]] 
        {() | list poke path ("#-2" "#3" "#-4") value 999}
          [[[],[],[999,[],[],[]]],[]]
  
      it mixes well with keyed lists, as long as enough elements exist. 
        {* (:a (2 1) :b (3 4) :c (4 5)) | list poke path ("#1" "#4") value 999}
          {"a":[2,1,[],999],"b":[3,4],"c":[4,5]} 
        {* (:a (2 1) :b (3 4) :c (4 5)) | list poke path ("#1" "#-6") value 999}
          {"a":[999,[],[],[],2,1],"b":[3,4],"c":[4,5]}        
        {* (:a {* (:aa 1 :ab 2)} :b {* (:ba 1 :bb 2)} :c {* (:ca 1 :cb 2)}) | list poke path ("#2" "#2") value 999}
          {"a":{"aa":1,"ab":2},"b":{"ba":1,"bb":999},"c":{"ca":1,"cb":2}} 
      
      but if there are gaps in your keyed list the results might be unexpected -- the generated keys are consecutive integers (offset by one million to avoid common collisions). 
      this behavior is likely to change; please don't rely on generated keys.
        {* (:a 1 :b 2 :c 3) | list poke path ("#5") value 999}
          {"1000000":[],"1000001":999,"a":1,"b":2,"c":3}
        {* (:a 1 :b 2 :c 3) | list poke path ("#5") value 999 | sort}
          [[],1,2,3,999]
        
        
    by star:
      
      {(2 3 4) | list poke path "*" value 999}
        [999,999,999]
      {((2 1) (3 4) (4 5)) | list poke path "*" value 999}
        [999,999,999]
      {((2 1) (3 4) (4 5)) | list poke path ("*" "#2") value 999}
        [[2,999],[3,999],[4,999]]
      {((2 1) (3 4) (4 5)) | list poke path ("#2" "*") value 999}
        [[2,1],[999,999],[4,5]]
      {((2 1) (3 4) (4 5)) | list poke path ("*" "*") value 999}
        [[999,999],[999,999],[999,999]]
        
      stars generate a new empty list for each missing (or scalar) level. (BUG)
        {() | list poke path ("*") value 999}
          []
        {() | list poke path ("*" "*") value 999}
          [[]]
        {(1 2 3) | list poke path ("*" "*") value 999}
          [[],[],[]]
        {(1 2 3) | list poke path ("*" "*" "*") value 999}
          [[[]],[[]],[[]]]
        {(1 2 3) | list poke path ("*" "*" "#2") value 999}
          [[[],999],[[],999],[[],999]]
          
      
    by list:
      
      {* (:a 1 :b 2 :c 3) | list poke path ( (:a :b) ) value 999}
        {"a":999,"b":999,"c":3}
      {* (:a 1 :b 2 :c 3) | list poke path ( (:d :e) ) value 999}
        {"a":1,"b":2,"c":3,"d":999,"e":999}
      {* (:a 1 :b 2 :c 3) | list poke path ( ("#1" "#3") ) value 999}
        {"a":999,"b":2,"c":999}
      {((2 1) (3 4) (4 5)) | list poke path ("*" ("#2" "#4") ) value 999}
        [[2,999,[],999],[3,999,[],999],[4,999,[],999]]
        
      generating a new list
        {* (:a 1 :b 2 :c 3) | list poke path ( "#2" ("#2" "#6" "#4") ) value 999}
          {"a":1,"b":[[],999,[],999,[],999],"c":3}
        
      generating a new list (BUG)
        {* (:a 1 :b 2 :c 3) | list poke path ( :b ("#2" "#6" "#4") ) value 999}
          {"a":1,"b":[[],999,[],999,[],999],"c":3}
        
      generating a new keyed list (BUG)
        {* (:a 1 :b 2 :c 3) | list poke path ( "#2" (:d :e) ) value 999}
          {"a":1,"b":{"d":999,"e":999},"c":3}
  
      double list all the way (BUG)
        {((2 1) (3 4) (4 5)) | list poke path ( ("#1" "#3") ("#2" "#4") ) value 999}
          [[2,999,[],999],[3,4],[4,999,[],999]]
  
  
  
  <h2>COMMAND EXAMPLES</h2>
  
negative.code:           42
          {10 | (__ __) | add __ | add 1 | add}
            42
  MAGIC PIPE TESTS
  
    The magic pipe has two uses: to explicitly connect two segments, and to access the Process's input value
  
    Case 1: explicit connection. Each of these also has an implicit connection, but only the first example uses it because the others have no additional param space (add only takes two params).
      {21 | add __}
        42
      {21 | add 21 to __}
        42
      {21 | add __ to 21}
        42
      {21 | add __ to __}
        42
  
    Case 1a: blocking implicit connection. The double pipe doesn't pass values implicitly, but you can still use the magic pipe to explicitly link them. Useful for commands that have multiple parameters.
      {42 || add __}
        42
      {21 || add 21 to __}
        42
  
    Case 1b: carry along. You can use a pipe to carry the value through segments.
      {42 | __}
        42
      {42 | __ | __}
        42
      
    Case 1c: duplication. You can use pipes in lists to duplicate the previous value
      {42 | (__)}
        [42]
      {42 | (__ __)}
        [42,42]
      {42 | (:x __ __)}
        ["x",42,42]
      {42 | (__ :x __)}
        [42,"x",42]
      {42 | (__ __ :x)}
        [42,42,"x"]
      
      {21 | add (__)}
        [42]
      {21 | add (__ __)}
        [42,42]
      {21 | add (-1 __ __)}
        [20,42,42]
      {21 | add (__ -1 __)}
        [42,20,42]
      {21 | add (__ __ -1)}
        [42,42,20]
  
  
    Rethinking Case 2. Having two different meanings of __ is probably overly complicated. I still like the idea of imagining the process input peeking in through the beginning of the pipeline, and I'd like to use that some day for things like {(1 2 3) | map "{add 1}"} but if we're going to be explicit about it why not use a different symbol? 
    [well, for one reason, some aliases have pipes in them: {(1 0 3) | map "{then :ham else :foo}"} -> (:ham :foo :ham) via front-pipes]
    maybe... maybe having ({__} {__}) freak out and do stupid things is reasonable, in the same way that other languages give syntax errors for stupid things. it's hard making a language with no real errors!
    and it's not like that construct is really that stupid -- if you really want the process input maybe that should give it to you? or... no, it's really stupid. it's inside another pipeline, so it can't be the outermost thing in the process. it should probably just return nothing, or "". Probably ("{__}" "{__}") -> ("" "") also. 
    BUT, {(1 2 3) | map "{__}"} -> (1 2 3). We really need an identity block. It's just that in the above it's getting the identity of nothing. 
    
  
  
  
    Case 2: access to process input. These are simple cases involving a single pipeline. Notice that the magic pipe must be in the first segment to access the process's input value. Magic pipes in later segments will reference the previous segment value.
    
      ----- thoughts on this:
      - if we made 'process input' a different symbol we wouldn't have embedded pipeline reference issues 
        - referencing the previous segment from inside a list is an important case
        - is it the only case??
      - starting a pipeline with __ is beautifully simple
        - it clearly indicates the intention of pulling in outside input
        - it demonstrates the linear nature of a pipeline: one thing in, one thing out
        - we lose this if we allow references inside a pipeline (oh we're doing that already oh dear)
      - the block case with multiple pipelines each referencing input is important, because
        - we want those to be able to run in parallel
        - a given pipeline should work the same regardless of context
        - so we can't just rely on 'first use' of __ and alias it after
      
      so it sounds like a different symbol is in order to refer universally to the input.
      OR we do something fiddly like {__} means input if it's outermost but embedded it never does (yuck).
      //   {__ | add 1}
      //   {_in | add 1}
      //   {*in | add 1}
      //   {___ | add 1}
      
      er... if it's inside a string, it maps to '*in'.
      if it's inside a list, it maps to prevval.
      is it that simple?
      // this is a pipe
      // ceci n'est pas une pipe
      
      
      
    
      {(1 2 3) | map block "{__ | add 4}"}
        [5,6,7]
      {(1 2 3) | map block "{add __ to 4}"}
        [5,6,7]
      {(1 2 3) | map block "{add __ to __}"}
        [2,4,6]
      {(1 2 3) | map block "{__}"}
        [1,2,3]
      {(1 2 3) | map block "{__ | __}"}
        [1,2,3]
      {(1 2 3) | map block "{__ | __ | add 1}"}
        [2,3,4]
      {(1 2 3) | map block "{__ | add 1 | __ | add 1}"}
        [3,4,5]
    
    Case 2a: block-level access. Multiple pipelines in a block can each access the process input.
      {begin foo | each data (1 2 3)} {__ | add 3} x {__ | add 7} ::{end foo}
        4 x 8 :: 5 x 9 :: 6 x 10 ::
      {begin foo | each data (1 2 3)} {add 3 to __} x {add __ to 7} ::{end foo}
        4 x 8 :: 5 x 9 :: 6 x 10 ::
    
    You can reframe the above like this:
      {(1 2 3) | each block "{__ | (" " {__in | add 3} " x " {__in | add 7} " ::") | join}"}
        4 x 8 :: 5 x 9 :: 6 x 10 ::
    
    Notes:
      To connect to the process input you must explicitly add the magic pipe to the first segment:
        {(1 2 3) | map block "{__ | add to 4}"}
          [5,6,7]
        {(1 2 3) | map block "{add to 4}" // bad}
          [4,4,4]
        {(1 2 3) | map block "{__ | add 4}"}
          [5,6,7]
        {(1 2 3) | map block "{add 4}" // bad}
          [4,4,4]
      
      
  ////    //The first segment of an inline pipeline also grab the process input instead of the previous segment value -- this is almost certainly not what you want. 
  ////THINK: how does this square off with __.foo? that essentially becomes {__ | list peek path (:foo)} and could be a param value or in a list. so {1 | ({__} {__})} should be (1 1) by that logic. what was the issue with that?
  ////If, while using a pipeline as a param value, you want access to the previous pipe segment's value, then you should either refactor the pipeline to do the processing beforehand (as above), or assign the value to a pipeline var.
  
  
      NEW RULES!
      - "{__}" links to process input
      - {__} links to previous value
      so: if it's in a string, it's input.
          if it's in a list or param value it's previous value.
  
  
        {20 | add {__ | add 2}}
          42
        {20 | add {__ | add 2} to __}
          42
      
        {21 | join (__ " " __) on ""}
          21 21
        {21 | ( {__ | add 1} " " {__ | add 2} ) | join}
          22 23
        {21 | ( {add 1 to __} " " {add __ to 2} ) | join}
          22 23
        {21 | >a | ( {_a | add 1} " " {_a | add 2} ) | join}
          22 23
    
        {40 | add {__} to 2}
          42
        {21 | add {__} to __}
          42
        {21 | add __ to {__}}
          42
        {21 | add {__} to {__}}
          42
        {20 | ( {__} 2 __ ) | add}
          42
        {20 | ( __ 2 {__} ) | add}
          42
        {20 | ( {__} 2 {__} ) | add}
          42
      
      Double pipes are also used to squelch output from a pipeline:
        {42 ||}
          
        {(1 2 3) | map block "{__ | add 1 ||}"}
          ["","",""]
  
  
  <h2>In Depth: Variables</h2>
  