about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--075duplex_list.mu308
-rw-r--r--edit/001-editor.mu20
-rw-r--r--edit/002-typing.mu28
-rw-r--r--edit/003-shortcuts.mu60
-rw-r--r--edit/005-sandbox.mu6
-rw-r--r--edit/006-sandbox-edit.mu2
-rw-r--r--edit/011-editor-undo.mu38
-rw-r--r--sandbox/001-editor.mu20
-rw-r--r--sandbox/002-typing.mu28
-rw-r--r--sandbox/003-shortcuts.mu60
-rw-r--r--sandbox/005-sandbox.mu6
-rw-r--r--sandbox/006-sandbox-edit.mu2
-rw-r--r--sandbox/011-editor-undo.mu38
13 files changed, 308 insertions, 308 deletions
diff --git a/075duplex_list.mu b/075duplex_list.mu
index 15f07f1c..02bb3152 100644
--- a/075duplex_list.mu
+++ b/075duplex_list.mu
@@ -6,7 +6,7 @@ container duplex-list:_elem [
   prev:address:duplex-list:_elem
 ]
 
-recipe push-duplex x:_elem, in:address:duplex-list:_elem -> result:address:duplex-list:_elem [
+recipe push x:_elem, in:address:duplex-list:_elem -> result:address:duplex-list:_elem [
   local-scope
   load-ingredients
   result <- new {(duplex-list _elem): type}
@@ -19,21 +19,21 @@ recipe push-duplex x:_elem, in:address:duplex-list:_elem -> result:address:duple
   *prev <- copy result
 ]
 
-recipe first-duplex in:address:duplex-list:_elem -> result:_elem [
+recipe first in:address:duplex-list:_elem -> result:_elem [
   local-scope
   load-ingredients
   reply-unless in, 0
   result <- get *in, value:offset
 ]
 
-recipe next-duplex in:address:duplex-list:_elem -> result:address:duplex-list:_elem [
+recipe next in:address:duplex-list:_elem -> result:address:duplex-list:_elem [
   local-scope
   load-ingredients
   reply-unless in, 0
   result <- get *in, next:offset
 ]
 
-recipe prev-duplex in:address:duplex-list:_elem -> result:address:duplex-list:_elem [
+recipe prev in:address:duplex-list:_elem -> result:address:duplex-list:_elem [
   local-scope
   load-ingredients
   reply-unless in, 0
@@ -46,23 +46,23 @@ scenario duplex-list-handling [
     # reserve locations 0, 1 and 2 to check for missing null check
     1:number <- copy 34
     2:number <- copy 35
-    3:address:duplex-list:character <- push-duplex 3, 0
-    3:address:duplex-list:character <- push-duplex 4, 3:address:duplex-list:character
-    3:address:duplex-list:character <- push-duplex 5, 3:address:duplex-list:character
+    3:address:duplex-list:character <- push 3, 0
+    3:address:duplex-list:character <- push 4, 3:address:duplex-list:character
+    3:address:duplex-list:character <- push 5, 3:address:duplex-list:character
     4:address:duplex-list:character <- copy 3:address:duplex-list:character
-    5:character <- first-duplex 4:address:duplex-list:character
-    4:address:duplex-list:character <- next-duplex 4:address:duplex-list:character
-    6:character <- first-duplex 4:address:duplex-list:character
-    4:address:duplex-list:character <- next-duplex 4:address:duplex-list:character
-    7:character <- first-duplex 4:address:duplex-list:character
-    8:address:duplex-list:character <- next-duplex 4:address:duplex-list:character
-    9:character <- first-duplex 8:address:duplex-list:character
-    10:address:duplex-list:character <- next-duplex 8:address:duplex-list:character
-    11:address:duplex-list:character <- prev-duplex 8:address:duplex-list:character
-    4:address:duplex-list:character <- prev-duplex 4:address:duplex-list:character
-    12:character <- first-duplex 4:address:duplex-list:character
-    4:address:duplex-list:character <- prev-duplex 4:address:duplex-list:character
-    13:character <- first-duplex 4:address:duplex-list:character
+    5:character <- first 4:address:duplex-list:character
+    4:address:duplex-list:character <- next 4:address:duplex-list:character
+    6:character <- first 4:address:duplex-list:character
+    4:address:duplex-list:character <- next 4:address:duplex-list:character
+    7:character <- first 4:address:duplex-list:character
+    8:address:duplex-list:character <- next 4:address:duplex-list:character
+    9:character <- first 8:address:duplex-list:character
+    10:address:duplex-list:character <- next 8:address:duplex-list:character
+    11:address:duplex-list:character <- prev 8:address:duplex-list:character
+    4:address:duplex-list:character <- prev 4:address:duplex-list:character
+    12:character <- first 4:address:duplex-list:character
+    4:address:duplex-list:character <- prev 4:address:duplex-list:character
+    13:character <- first 4:address:duplex-list:character
     14:boolean <- equal 3:address:duplex-list:character, 4:address:duplex-list:character
   ]
   memory-should-contain [
@@ -83,7 +83,7 @@ scenario duplex-list-handling [
 ]
 
 # Inserts 'x' after 'in'. Returns some pointer into the list.
-recipe insert-duplex x:_elem, in:address:duplex-list:_elem -> new-node:address:duplex-list:_elem [
+recipe insert x:_elem, in:address:duplex-list:_elem -> new-node:address:duplex-list:_elem [
   local-scope
   load-ingredients
   new-node <- new {(duplex-list _elem): type}
@@ -109,26 +109,26 @@ recipe insert-duplex x:_elem, in:address:duplex-list:_elem -> new-node:address:d
 
 scenario inserting-into-duplex-list [
   run [
-    1:address:duplex-list:character <- push-duplex 3, 0
-    1:address:duplex-list:character <- push-duplex 4, 1:address:duplex-list:character
-    1:address:duplex-list:character <- push-duplex 5, 1:address:duplex-list:character
-    2:address:duplex-list:character <- next-duplex 1:address:duplex-list:character  # 2 points inside list
-    2:address:duplex-list:character <- insert-duplex 6, 2:address:duplex-list:character
+    1:address:duplex-list:character <- push 3, 0
+    1:address:duplex-list:character <- push 4, 1:address:duplex-list:character
+    1:address:duplex-list:character <- push 5, 1:address:duplex-list:character
+    2:address:duplex-list:character <- next 1:address:duplex-list:character  # 2 points inside list
+    2:address:duplex-list:character <- insert 6, 2:address:duplex-list:character
     # check structure like before
     2:address:duplex-list:character <- copy 1:address:duplex-list:character
-    3:character <- first-duplex 2:address:duplex-list:character
-    2:address:duplex-list:character <- next-duplex 2:address:duplex-list:character
-    4:character <- first-duplex 2:address:duplex-list:character
-    2:address:duplex-list:character <- next-duplex 2:address:duplex-list:character
-    5:character <- first-duplex 2:address:duplex-list:character
-    2:address:duplex-list:character <- next-duplex 2:address:duplex-list:character
-    6:character <- first-duplex 2:address:duplex-list:character
-    2:address:duplex-list:character <- prev-duplex 2:address:duplex-list:character
-    7:character <- first-duplex 2:address:duplex-list:character
-    2:address:duplex-list:character <- prev-duplex 2:address:duplex-list:character
-    8:character <- first-duplex 2:address:duplex-list:character
-    2:address:duplex-list:character <- prev-duplex 2:address:duplex-list:character
-    9:character <- first-duplex 2:address:duplex-list:character
+    3:character <- first 2:address:duplex-list:character
+    2:address:duplex-list:character <- next 2:address:duplex-list:character
+    4:character <- first 2:address:duplex-list:character
+    2:address:duplex-list:character <- next 2:address:duplex-list:character
+    5:character <- first 2:address:duplex-list:character
+    2:address:duplex-list:character <- next 2:address:duplex-list:character
+    6:character <- first 2:address:duplex-list:character
+    2:address:duplex-list:character <- prev 2:address:duplex-list:character
+    7:character <- first 2:address:duplex-list:character
+    2:address:duplex-list:character <- prev 2:address:duplex-list:character
+    8:character <- first 2:address:duplex-list:character
+    2:address:duplex-list:character <- prev 2:address:duplex-list:character
+    9:character <- first 2:address:duplex-list:character
     10:boolean <- equal 1:address:duplex-list:character, 2:address:duplex-list:character
   ]
   memory-should-contain [
@@ -145,27 +145,27 @@ scenario inserting-into-duplex-list [
 
 scenario inserting-at-end-of-duplex-list [
   run [
-    1:address:duplex-list:character <- push-duplex 3, 0
-    1:address:duplex-list:character <- push-duplex 4, 1:address:duplex-list:character
-    1:address:duplex-list:character <- push-duplex 5, 1:address:duplex-list:character
-    2:address:duplex-list:character <- next-duplex 1:address:duplex-list:character  # 2 points inside list
-    2:address:duplex-list:character <- next-duplex 2:address:duplex-list:character  # now at end of list
-    2:address:duplex-list:character <- insert-duplex 6, 2:address:duplex-list:character
+    1:address:duplex-list:character <- push 3, 0
+    1:address:duplex-list:character <- push 4, 1:address:duplex-list:character
+    1:address:duplex-list:character <- push 5, 1:address:duplex-list:character
+    2:address:duplex-list:character <- next 1:address:duplex-list:character  # 2 points inside list
+    2:address:duplex-list:character <- next 2:address:duplex-list:character  # now at end of list
+    2:address:duplex-list:character <- insert 6, 2:address:duplex-list:character
     # check structure like before
     2:address:duplex-list:character <- copy 1:address:duplex-list:character
-    3:character <- first-duplex 2:address:duplex-list:character
-    2:address:duplex-list:character <- next-duplex 2:address:duplex-list:character
-    4:character <- first-duplex 2:address:duplex-list:character
-    2:address:duplex-list:character <- next-duplex 2:address:duplex-list:character
-    5:character <- first-duplex 2:address:duplex-list:character
-    2:address:duplex-list:character <- next-duplex 2:address:duplex-list:character
-    6:character <- first-duplex 2:address:duplex-list:character
-    2:address:duplex-list:character <- prev-duplex 2:address:duplex-list:character
-    7:character <- first-duplex 2:address:duplex-list:character
-    2:address:duplex-list:character <- prev-duplex 2:address:duplex-list:character
-    8:character <- first-duplex 2:address:duplex-list:character
-    2:address:duplex-list:character <- prev-duplex 2:address:duplex-list:character
-    9:character <- first-duplex 2:address:duplex-list:character
+    3:character <- first 2:address:duplex-list:character
+    2:address:duplex-list:character <- next 2:address:duplex-list:character
+    4:character <- first 2:address:duplex-list:character
+    2:address:duplex-list:character <- next 2:address:duplex-list:character
+    5:character <- first 2:address:duplex-list:character
+    2:address:duplex-list:character <- next 2:address:duplex-list:character
+    6:character <- first 2:address:duplex-list:character
+    2:address:duplex-list:character <- prev 2:address:duplex-list:character
+    7:character <- first 2:address:duplex-list:character
+    2:address:duplex-list:character <- prev 2:address:duplex-list:character
+    8:character <- first 2:address:duplex-list:character
+    2:address:duplex-list:character <- prev 2:address:duplex-list:character
+    9:character <- first 2:address:duplex-list:character
     10:boolean <- equal 1:address:duplex-list:character, 2:address:duplex-list:character
   ]
   memory-should-contain [
@@ -182,25 +182,25 @@ scenario inserting-at-end-of-duplex-list [
 
 scenario inserting-after-start-of-duplex-list [
   run [
-    1:address:duplex-list:character <- push-duplex 3, 0
-    1:address:duplex-list:character <- push-duplex 4, 1:address:duplex-list:character
-    1:address:duplex-list:character <- push-duplex 5, 1:address:duplex-list:character
-    2:address:duplex-list:character <- insert-duplex 6, 1:address:duplex-list:character
+    1:address:duplex-list:character <- push 3, 0
+    1:address:duplex-list:character <- push 4, 1:address:duplex-list:character
+    1:address:duplex-list:character <- push 5, 1:address:duplex-list:character
+    2:address:duplex-list:character <- insert 6, 1:address:duplex-list:character
     # check structure like before
     2:address:duplex-list:character <- copy 1:address:duplex-list:character
-    3:character <- first-duplex 2:address:duplex-list:character
-    2:address:duplex-list:character <- next-duplex 2:address:duplex-list:character
-    4:character <- first-duplex 2:address:duplex-list:character
-    2:address:duplex-list:character <- next-duplex 2:address:duplex-list:character
-    5:character <- first-duplex 2:address:duplex-list:character
-    2:address:duplex-list:character <- next-duplex 2:address:duplex-list:character
-    6:character <- first-duplex 2:address:duplex-list:character
-    2:address:duplex-list:character <- prev-duplex 2:address:duplex-list:character
-    7:character <- first-duplex 2:address:duplex-list:character
-    2:address:duplex-list:character <- prev-duplex 2:address:duplex-list:character
-    8:character <- first-duplex 2:address:duplex-list:character
-    2:address:duplex-list:character <- prev-duplex 2:address:duplex-list:character
-    9:character <- first-duplex 2:address:duplex-list:character
+    3:character <- first 2:address:duplex-list:character
+    2:address:duplex-list:character <- next 2:address:duplex-list:character
+    4:character <- first 2:address:duplex-list:character
+    2:address:duplex-list:character <- next 2:address:duplex-list:character
+    5:character <- first 2:address:duplex-list:character
+    2:address:duplex-list:character <- next 2:address:duplex-list:character
+    6:character <- first 2:address:duplex-list:character
+    2:address:duplex-list:character <- prev 2:address:duplex-list:character
+    7:character <- first 2:address:duplex-list:character
+    2:address:duplex-list:character <- prev 2:address:duplex-list:character
+    8:character <- first 2:address:duplex-list:character
+    2:address:duplex-list:character <- prev 2:address:duplex-list:character
+    9:character <- first 2:address:duplex-list:character
     10:boolean <- equal 1:address:duplex-list:character, 2:address:duplex-list:character
   ]
   memory-should-contain [
@@ -220,7 +220,7 @@ scenario inserting-after-start-of-duplex-list [
 #
 # Returns null if and only if list is empty. Beware: in that case any pointers
 # to the head are now invalid.
-recipe remove-duplex in:address:duplex-list:_elem -> next-node:address:duplex-list:_elem [
+recipe remove in:address:duplex-list:_elem -> next-node:address:duplex-list:_elem [
   local-scope
   load-ingredients
   # if 'in' is null, return
@@ -252,20 +252,20 @@ recipe remove-duplex in:address:duplex-list:_elem -> next-node:address:duplex-li
 
 scenario removing-from-duplex-list [
   run [
-    1:address:duplex-list:character <- push-duplex 3, 0
-    1:address:duplex-list:character <- push-duplex 4, 1:address:duplex-list:character
-    1:address:duplex-list:character <- push-duplex 5, 1:address:duplex-list:character
-    2:address:duplex-list:character <- next-duplex 1:address:duplex-list:character  # 2 points at second element
-    2:address:duplex-list:character <- remove-duplex 2:address:duplex-list:character
+    1:address:duplex-list:character <- push 3, 0
+    1:address:duplex-list:character <- push 4, 1:address:duplex-list:character
+    1:address:duplex-list:character <- push 5, 1:address:duplex-list:character
+    2:address:duplex-list:character <- next 1:address:duplex-list:character  # 2 points at second element
+    2:address:duplex-list:character <- remove 2:address:duplex-list:character
     3:boolean <- equal 2:address:duplex-list:character, 0
     # check structure like before
     2:address:duplex-list:character <- copy 1:address:duplex-list:character
-    4:character <- first-duplex 2:address:duplex-list:character
-    2:address:duplex-list:character <- next-duplex 2:address:duplex-list:character
-    5:character <- first-duplex 2:address:duplex-list:character
-    6:address:duplex-list:character <- next-duplex 2:address:duplex-list:character
-    2:address:duplex-list:character <- prev-duplex 2:address:duplex-list:character
-    7:character <- first-duplex 2:address:duplex-list:character
+    4:character <- first 2:address:duplex-list:character
+    2:address:duplex-list:character <- next 2:address:duplex-list:character
+    5:character <- first 2:address:duplex-list:character
+    6:address:duplex-list:character <- next 2:address:duplex-list:character
+    2:address:duplex-list:character <- prev 2:address:duplex-list:character
+    7:character <- first 2:address:duplex-list:character
     8:boolean <- equal 1:address:duplex-list:character, 2:address:duplex-list:character
   ]
   memory-should-contain [
@@ -280,19 +280,19 @@ scenario removing-from-duplex-list [
 
 scenario removing-from-start-of-duplex-list [
   run [
-    1:address:duplex-list:character <- push-duplex 3, 0
-    1:address:duplex-list:character <- push-duplex 4, 1:address:duplex-list:character
-    1:address:duplex-list:character <- push-duplex 5, 1:address:duplex-list:character
+    1:address:duplex-list:character <- push 3, 0
+    1:address:duplex-list:character <- push 4, 1:address:duplex-list:character
+    1:address:duplex-list:character <- push 5, 1:address:duplex-list:character
     # removing from head? return value matters.
-    1:address:duplex-list:character <- remove-duplex 1:address:duplex-list:character
+    1:address:duplex-list:character <- remove 1:address:duplex-list:character
     # check structure like before
     2:address:duplex-list:character <- copy 1:address:duplex-list:character
-    3:character <- first-duplex 2:address:duplex-list:character
-    2:address:duplex-list:character <- next-duplex 2:address:duplex-list:character
-    4:character <- first-duplex 2:address:duplex-list:character
-    5:address:duplex-list:character <- next-duplex 2:address:duplex-list:character
-    2:address:duplex-list:character <- prev-duplex 2:address:duplex-list:character
-    6:character <- first-duplex 2:address:duplex-list:character
+    3:character <- first 2:address:duplex-list:character
+    2:address:duplex-list:character <- next 2:address:duplex-list:character
+    4:character <- first 2:address:duplex-list:character
+    5:address:duplex-list:character <- next 2:address:duplex-list:character
+    2:address:duplex-list:character <- prev 2:address:duplex-list:character
+    6:character <- first 2:address:duplex-list:character
     7:boolean <- equal 1:address:duplex-list:character, 2:address:duplex-list:character
   ]
   memory-should-contain [
@@ -306,22 +306,22 @@ scenario removing-from-start-of-duplex-list [
 
 scenario removing-from-end-of-duplex-list [
   run [
-    1:address:duplex-list:character <- push-duplex 3, 0
-    1:address:duplex-list:character <- push-duplex 4, 1:address:duplex-list:character
-    1:address:duplex-list:character <- push-duplex 5, 1:address:duplex-list:character
+    1:address:duplex-list:character <- push 3, 0
+    1:address:duplex-list:character <- push 4, 1:address:duplex-list:character
+    1:address:duplex-list:character <- push 5, 1:address:duplex-list:character
     # delete last element
-    2:address:duplex-list:character <- next-duplex 1:address:duplex-list:character
-    2:address:duplex-list:character <- next-duplex 2:address:duplex-list:character
-    2:address:duplex-list:character <- remove-duplex 2:address:duplex-list:character
+    2:address:duplex-list:character <- next 1:address:duplex-list:character
+    2:address:duplex-list:character <- next 2:address:duplex-list:character
+    2:address:duplex-list:character <- remove 2:address:duplex-list:character
     3:boolean <- equal 2:address:duplex-list:character, 0
     # check structure like before
     2:address:duplex-list:character <- copy 1:address:duplex-list:character
-    4:character <- first-duplex 2:address:duplex-list:character
-    2:address:duplex-list:character <- next-duplex 2:address:duplex-list:character
-    5:character <- first-duplex 2:address:duplex-list:character
-    6:address:duplex-list:character <- next-duplex 2:address:duplex-list:character
-    2:address:duplex-list:character <- prev-duplex 2:address:duplex-list:character
-    7:character <- first-duplex 2:address:duplex-list:character
+    4:character <- first 2:address:duplex-list:character
+    2:address:duplex-list:character <- next 2:address:duplex-list:character
+    5:character <- first 2:address:duplex-list:character
+    6:address:duplex-list:character <- next 2:address:duplex-list:character
+    2:address:duplex-list:character <- prev 2:address:duplex-list:character
+    7:character <- first 2:address:duplex-list:character
     8:boolean <- equal 1:address:duplex-list:character, 2:address:duplex-list:character
   ]
   memory-should-contain [
@@ -336,8 +336,8 @@ scenario removing-from-end-of-duplex-list [
 
 scenario removing-from-singleton-list [
   run [
-    1:address:duplex-list:character <- push-duplex 3, 0
-    2:address:duplex-list:character <- remove-duplex 1:address:duplex-list:character
+    1:address:duplex-list:character <- push 3, 0
+    2:address:duplex-list:character <- remove 1:address:duplex-list:character
     3:address:duplex-list:character <- get *1:address:duplex-list:character, next:offset
     4:address:duplex-list:character <- get *1:address:duplex-list:character, prev:offset
   ]
@@ -350,7 +350,7 @@ scenario removing-from-singleton-list [
 
 # remove values between 'start' and 'end' (both exclusive)
 # also clear pointers back out from start/end for hygiene
-recipe remove-duplex-between start:address:duplex-list:_elem, end:address:duplex-list:_elem -> start:address:duplex-list:_elem [
+recipe remove-between start:address:duplex-list:_elem, end:address:duplex-list:_elem -> start:address:duplex-list:_elem [
   local-scope
   load-ingredients
   reply-unless start
@@ -373,25 +373,25 @@ recipe remove-duplex-between start:address:duplex-list:_elem, end:address:duplex
 
 scenario remove-range [
   # construct a duplex list with six elements [13, 14, 15, 16, 17, 18]
-  1:address:duplex-list:character <- push-duplex 18, 0
-  1:address:duplex-list:character <- push-duplex 17, 1:address:duplex-list:character
-  1:address:duplex-list:character <- push-duplex 16, 1:address:duplex-list:character
-  1:address:duplex-list:character <- push-duplex 15, 1:address:duplex-list:character
-  1:address:duplex-list:character <- push-duplex 14, 1:address:duplex-list:character
-  1:address:duplex-list:character <- push-duplex 13, 1:address:duplex-list:character
+  1:address:duplex-list:character <- push 18, 0
+  1:address:duplex-list:character <- push 17, 1:address:duplex-list:character
+  1:address:duplex-list:character <- push 16, 1:address:duplex-list:character
+  1:address:duplex-list:character <- push 15, 1:address:duplex-list:character
+  1:address:duplex-list:character <- push 14, 1:address:duplex-list:character
+  1:address:duplex-list:character <- push 13, 1:address:duplex-list:character
   run [
     # delete 16 onwards
     # first pointer: to the third element
-    2:address:duplex-list:character <- next-duplex 1:address:duplex-list:character
-    2:address:duplex-list:character <- next-duplex 2:address:duplex-list:character
-    2:address:duplex-list:character <- remove-duplex-between 2:address:duplex-list:character, 0
+    2:address:duplex-list:character <- next 1:address:duplex-list:character
+    2:address:duplex-list:character <- next 2:address:duplex-list:character
+    2:address:duplex-list:character <- remove-between 2:address:duplex-list:character, 0
     # now check the list
     4:character <- get *1:address:duplex-list:character, value:offset
-    5:address:duplex-list:character <- next-duplex 1:address:duplex-list:character
+    5:address:duplex-list:character <- next 1:address:duplex-list:character
     6:character <- get *5:address:duplex-list:character, value:offset
-    7:address:duplex-list:character <- next-duplex 5:address:duplex-list:character
+    7:address:duplex-list:character <- next 5:address:duplex-list:character
     8:character <- get *7:address:duplex-list:character, value:offset
-    9:address:duplex-list:character <- next-duplex 7:address:duplex-list:character
+    9:address:duplex-list:character <- next 7:address:duplex-list:character
   ]
   memory-should-contain [
     4 <- 13
@@ -403,29 +403,29 @@ scenario remove-range [
 
 scenario remove-range-to-end [
   # construct a duplex list with six elements [13, 14, 15, 16, 17, 18]
-  1:address:duplex-list:character <- push-duplex 18, 0
-  1:address:duplex-list:character <- push-duplex 17, 1:address:duplex-list:character
-  1:address:duplex-list:character <- push-duplex 16, 1:address:duplex-list:character
-  1:address:duplex-list:character <- push-duplex 15, 1:address:duplex-list:character
-  1:address:duplex-list:character <- push-duplex 14, 1:address:duplex-list:character
-  1:address:duplex-list:character <- push-duplex 13, 1:address:duplex-list:character
+  1:address:duplex-list:character <- push 18, 0
+  1:address:duplex-list:character <- push 17, 1:address:duplex-list:character
+  1:address:duplex-list:character <- push 16, 1:address:duplex-list:character
+  1:address:duplex-list:character <- push 15, 1:address:duplex-list:character
+  1:address:duplex-list:character <- push 14, 1:address:duplex-list:character
+  1:address:duplex-list:character <- push 13, 1:address:duplex-list:character
   run [
     # delete 15, 16 and 17
     # first pointer: to the third element
-    2:address:duplex-list:character <- next-duplex 1:address:duplex-list:character
+    2:address:duplex-list:character <- next 1:address:duplex-list:character
     # second pointer: to the fifth element
-    3:address:duplex-list:character <- next-duplex 2:address:duplex-list:character
-    3:address:duplex-list:character <- next-duplex 3:address:duplex-list:character
-    3:address:duplex-list:character <- next-duplex 3:address:duplex-list:character
-    3:address:duplex-list:character <- next-duplex 3:address:duplex-list:character
-    remove-duplex-between 2:address:duplex-list:character, 3:address:duplex-list:character
+    3:address:duplex-list:character <- next 2:address:duplex-list:character
+    3:address:duplex-list:character <- next 3:address:duplex-list:character
+    3:address:duplex-list:character <- next 3:address:duplex-list:character
+    3:address:duplex-list:character <- next 3:address:duplex-list:character
+    remove-between 2:address:duplex-list:character, 3:address:duplex-list:character
     # now check the list
     4:character <- get *1:address:duplex-list:character, value:offset
-    5:address:duplex-list:character <- next-duplex 1:address:duplex-list:character
+    5:address:duplex-list:character <- next 1:address:duplex-list:character
     6:character <- get *5:address:duplex-list:character, value:offset
-    7:address:duplex-list:character <- next-duplex 5:address:duplex-list:character
+    7:address:duplex-list:character <- next 5:address:duplex-list:character
     8:character <- get *7:address:duplex-list:character, value:offset
-    9:address:duplex-list:character <- next-duplex 7:address:duplex-list:character
+    9:address:duplex-list:character <- next 7:address:duplex-list:character
   ]
   memory-should-contain [
     4 <- 13
@@ -437,18 +437,18 @@ scenario remove-range-to-end [
 
 scenario remove-range-empty [
   # construct a duplex list with six elements [13, 14, 15, 16, 17, 18]
-  1:address:duplex-list:character <- push-duplex 14, 0
-  1:address:duplex-list:character <- push-duplex 13, 1:address:duplex-list:character
+  1:address:duplex-list:character <- push 14, 0
+  1:address:duplex-list:character <- push 13, 1:address:duplex-list:character
   run [
     # delete 16 onwards
     # first pointer: to the third element
-    2:address:duplex-list:character <- next-duplex 1:address:duplex-list:character
-    remove-duplex-between 1:address:duplex-list:character, 2:address:duplex-list:character
+    2:address:duplex-list:character <- next 1:address:duplex-list:character
+    remove-between 1:address:duplex-list:character, 2:address:duplex-list:character
     # now check the list
     4:character <- get *1:address:duplex-list:character, value:offset
-    5:address:duplex-list:character <- next-duplex 1:address:duplex-list:character
+    5:address:duplex-list:character <- next 1:address:duplex-list:character
     6:character <- get *5:address:duplex-list:character, value:offset
-    7:address:duplex-list:character <- next-duplex 5:address:duplex-list:character
+    7:address:duplex-list:character <- next 5:address:duplex-list:character
   ]
   memory-should-contain [
     4 <- 13
@@ -458,19 +458,19 @@ scenario remove-range-empty [
 ]
 
 # Inserts list beginning at 'new' after 'in'. Returns some pointer into the list.
-recipe insert-duplex-range in:address:duplex-list:_elem, start:address:duplex-list:_elem -> in:address:duplex-list:_elem [
+recipe insert-range in:address:duplex-list:_elem, start:address:duplex-list:_elem -> in:address:duplex-list:_elem [
   local-scope
   load-ingredients
   reply-unless in
   reply-unless start
   end:address:duplex-list:_elem <- copy start
   {
-    next:address:duplex-list:_elem <- next-duplex end/insert-range
+    next:address:duplex-list:_elem <- next end/insert-range
     break-unless next
     end <- copy next
     loop
   }
-  next:address:duplex-list:_elem <- next-duplex in
+  next:address:duplex-list:_elem <- next in
   dest:address:address:duplex-list:_elem <- get-address *end, next:offset
   *dest <- copy next
   {
@@ -484,10 +484,10 @@ recipe insert-duplex-range in:address:duplex-list:_elem, start:address:duplex-li
   *dest <- copy in
 ]
 
-recipe append-duplex in:address:duplex-list:_elem, new:address:duplex-list:_elem -> in:address:duplex-list:_elem [
+recipe append in:address:duplex-list:_elem, new:address:duplex-list:_elem -> in:address:duplex-list:_elem [
   local-scope
   load-ingredients
-  last:address:duplex-list:_elem <- last-duplex in
+  last:address:duplex-list:_elem <- last in
   dest:address:address:duplex-list:_elem <- get-address *last, next:offset
   *dest <- copy new
   reply-unless new
@@ -495,12 +495,12 @@ recipe append-duplex in:address:duplex-list:_elem, new:address:duplex-list:_elem
   *dest <- copy last
 ]
 
-recipe last-duplex in:address:duplex-list:_elem -> result:address:duplex-list:_elem [
+recipe last in:address:duplex-list:_elem -> result:address:duplex-list:_elem [
   local-scope
   load-ingredients
   result <- copy in
   {
-    next:address:duplex-list:_elem <- next-duplex result
+    next:address:duplex-list:_elem <- next result
     break-unless next
     result <- copy next
     loop
@@ -508,7 +508,7 @@ recipe last-duplex in:address:duplex-list:_elem -> result:address:duplex-list:_e
 ]
 
 # helper for debugging
-recipe dump-duplex-from x:address:duplex-list:_elem [
+recipe dump-from x:address:duplex-list:_elem [
   local-scope
   load-ingredients
   $print x, [: ]
@@ -516,7 +516,7 @@ recipe dump-duplex-from x:address:duplex-list:_elem [
     break-unless x
     c:_elem <- get *x, value:offset
     $print c, [ ]
-    x <- next-duplex x
+    x <- next x
     {
       is-newline?:boolean <- equal c, 10/newline
       break-unless is-newline?
diff --git a/edit/001-editor.mu b/edit/001-editor.mu
index 4b8da7a8..c74e6ac4 100644
--- a/edit/001-editor.mu
+++ b/edit/001-editor.mu
@@ -64,7 +64,7 @@ recipe new-editor s:address:array:character, screen:address:screen, left:number,
   x <- get-address *result, cursor-column:offset
   *x <- copy left
   init:address:address:duplex-list:character <- get-address *result, data:offset
-  *init <- push-duplex 167/§, 0/tail
+  *init <- push 167/§, 0/tail
   top-of-screen:address:address:duplex-list:character <- get-address *result, top-of-screen:offset
   *top-of-screen <- copy *init
   y:address:address:duplex-list:character <- get-address *result, before-cursor:offset
@@ -92,9 +92,9 @@ recipe insert-text editor:address:editor-data, text:address:array:character -> e
     done?:boolean <- greater-or-equal idx, len
     break-if done?
     c:character <- index *text, idx
-    insert-duplex c, curr
+    insert c, curr
     # next iter
-    curr <- next-duplex curr
+    curr <- next curr
     idx <- add idx, 1
     loop
   }
@@ -136,8 +136,8 @@ recipe render screen:address:screen, editor:address:editor-data -> last-row:numb
   right:number <- get *editor, right:offset
   # traversing editor
   curr:address:duplex-list:character <- get *editor, top-of-screen:offset
-  prev:address:duplex-list:character <- copy curr  # just in case curr becomes null and we can't compute prev-duplex
-  curr <- next-duplex curr
+  prev:address:duplex-list:character <- copy curr  # just in case curr becomes null and we can't compute prev
+  curr <- next curr
   # traversing screen
   +render-loop-initialization
   color:number <- copy 7/white
@@ -175,7 +175,7 @@ recipe render screen:address:screen, editor:address:editor-data -> last-row:numb
         left-of-cursor?:boolean <- lesser-than column, *cursor-column
         break-unless left-of-cursor?
         *cursor-column <- copy column
-        *before-cursor <- prev-duplex curr
+        *before-cursor <- prev curr
       }
       # clear rest of line in this window
       clear-line-delimited screen, column, right
@@ -183,8 +183,8 @@ recipe render screen:address:screen, editor:address:editor-data -> last-row:numb
       row <- add row, 1
       column <- copy left
       screen <- move-cursor screen, row, column
-      curr <- next-duplex curr
-      prev <- next-duplex prev
+      curr <- next curr
+      prev <- next prev
       loop +next-character:label
     }
     {
@@ -201,8 +201,8 @@ recipe render screen:address:screen, editor:address:editor-data -> last-row:numb
       loop +next-character:label
     }
     print-character screen, c, color
-    curr <- next-duplex curr
-    prev <- next-duplex prev
+    curr <- next curr
+    prev <- next prev
     column <- add column, 1
     loop
   }
diff --git a/edit/002-typing.mu b/edit/002-typing.mu
index e766926a..bc47e2d8 100644
--- a/edit/002-typing.mu
+++ b/edit/002-typing.mu
@@ -79,8 +79,8 @@ recipe snap-cursor screen:address:screen, editor:address:editor-data, target-row
   screen-height:number <- screen-height screen
   # count newlines until screen row
   curr:address:duplex-list:character <- get *editor, top-of-screen:offset
-  prev:address:duplex-list:character <- copy curr  # just in case curr becomes null and we can't compute prev-duplex
-  curr <- next-duplex curr
+  prev:address:duplex-list:character <- copy curr  # just in case curr becomes null and we can't compute prev
+  curr <- next curr
   row:number <- copy 1/top
   column:number <- copy left
   cursor-row:address:number <- get-address *editor, cursor-row:offset
@@ -120,8 +120,8 @@ recipe snap-cursor screen:address:screen, editor:address:editor-data, target-row
       # skip to next line
       row <- add row, 1
       column <- copy left
-      curr <- next-duplex curr
-      prev <- next-duplex prev
+      curr <- next curr
+      prev <- next prev
       loop +next-character:label
     }
     {
@@ -134,8 +134,8 @@ recipe snap-cursor screen:address:screen, editor:address:editor-data, target-row
       # don't increment curr/prev
       loop +next-character:label
     }
-    curr <- next-duplex curr
-    prev <- next-duplex prev
+    curr <- next curr
+    prev <- next prev
     column <- add column, 1
     loop
   }
@@ -199,8 +199,8 @@ recipe insert-at-cursor editor:address:editor-data, c:character, screen:address:
   local-scope
   load-ingredients
   before-cursor:address:address:duplex-list:character <- get-address *editor, before-cursor:offset
-  insert-duplex c, *before-cursor
-  *before-cursor <- next-duplex *before-cursor
+  insert c, *before-cursor
+  *before-cursor <- next *before-cursor
   cursor-row:address:number <- get-address *editor, cursor-row:offset
   cursor-column:address:number <- get-address *editor, cursor-column:offset
   left:number <- get *editor, left:offset
@@ -213,7 +213,7 @@ recipe insert-at-cursor editor:address:editor-data, c:character, screen:address:
   <insert-character-special-case>
   # but mostly we'll just move the cursor right
   *cursor-column <- add *cursor-column, 1
-  next:address:duplex-list:character <- next-duplex *before-cursor
+  next:address:duplex-list:character <- next *before-cursor
   {
     # at end of all text? no need to scroll? just print the character and leave
     at-end?:boolean <- equal next, 0/null
@@ -248,7 +248,7 @@ recipe insert-at-cursor editor:address:editor-data, c:character, screen:address:
       break-if at-newline?
       print-character screen, currc
       curr-column <- add curr-column, 1
-      curr <- next-duplex curr
+      curr <- next curr
       loop
     }
     go-render? <- copy 0/false
@@ -832,8 +832,8 @@ recipe insert-new-line-and-indent editor:address:editor-data, screen:address:scr
   right:number <- get *editor, right:offset
   screen-height:number <- screen-height screen
   # insert newline
-  insert-duplex 10/newline, *before-cursor
-  *before-cursor <- next-duplex *before-cursor
+  insert 10/newline, *before-cursor
+  *before-cursor <- next *before-cursor
   *cursor-row <- add *cursor-row, 1
   *cursor-column <- copy left
   # maybe scroll
@@ -848,7 +848,7 @@ recipe insert-new-line-and-indent editor:address:editor-data, screen:address:scr
   indent?:boolean <- get *editor, indent?:offset
   reply-unless indent?
   d:address:duplex-list:character <- get *editor, data:offset
-  end-of-previous-line:address:duplex-list:character <- prev-duplex *before-cursor
+  end-of-previous-line:address:duplex-list:character <- prev *before-cursor
   indent:number <- line-indent end-of-previous-line, d
   i:number <- copy 0
   {
@@ -870,7 +870,7 @@ recipe line-indent curr:address:duplex-list:character, start:address:duplex-list
   at-start?:boolean <- equal curr, start
   reply-if at-start?
   {
-    curr <- prev-duplex curr
+    curr <- prev curr
     break-unless curr
     at-start?:boolean <- equal curr, start
     break-if at-start?
diff --git a/edit/003-shortcuts.mu b/edit/003-shortcuts.mu
index f4c480d3..9c46c927 100644
--- a/edit/003-shortcuts.mu
+++ b/edit/003-shortcuts.mu
@@ -85,14 +85,14 @@ recipe delete-before-cursor editor:address:editor-data, screen:address:screen ->
   load-ingredients
   before-cursor:address:address:duplex-list:character <- get-address *editor, before-cursor:offset
   # if at start of text (before-cursor at § sentinel), return
-  prev:address:duplex-list:character <- prev-duplex *before-cursor
+  prev:address:duplex-list:character <- prev *before-cursor
   go-render?, backspaced-cell <- copy 0/no-more-render, 0/nothing-deleted
   reply-unless prev
   trace 10, [app], [delete-before-cursor]
   original-row:number <- get *editor, cursor-row:offset
   editor, scroll?:boolean <- move-cursor-coordinates-left editor
   backspaced-cell:address:duplex-list:character <- copy *before-cursor
-  remove-duplex *before-cursor  # will also neatly trim next/prev pointers in backspaced-cell/*before-cursor
+  remove *before-cursor  # will also neatly trim next/prev pointers in backspaced-cell/*before-cursor
   *before-cursor <- copy prev
   go-render? <- copy 1/true
   reply-if scroll?
@@ -105,7 +105,7 @@ recipe delete-before-cursor editor:address:editor-data, screen:address:screen ->
   reply-unless same-row?
   left:number <- get *editor, left:offset
   right:number <- get *editor, right:offset
-  curr:address:duplex-list:character <- next-duplex *before-cursor
+  curr:address:duplex-list:character <- next *before-cursor
   screen <- move-cursor screen, cursor-row, cursor-column
   curr-column:number <- copy cursor-column
   {
@@ -120,7 +120,7 @@ recipe delete-before-cursor editor:address:editor-data, screen:address:screen ->
     break-if at-newline?
     screen <- print-character screen, currc
     curr-column <- add curr-column, 1
-    curr <- next-duplex curr
+    curr <- next curr
     loop
   }
   # we're guaranteed not to be at the right margin
@@ -184,7 +184,7 @@ recipe previous-line-length curr:address:duplex-list:character, start:address:du
   at-start?:boolean <- equal curr, start
   reply-if at-start?
   {
-    curr <- prev-duplex curr
+    curr <- prev curr
     break-unless curr
     at-start?:boolean <- equal curr, start
     break-if at-start?
@@ -333,16 +333,16 @@ recipe delete-at-cursor editor:address:editor-data, screen:address:screen -> edi
   local-scope
   load-ingredients
   before-cursor:address:address:duplex-list:character <- get-address *editor, before-cursor:offset
-  deleted-cell:address:duplex-list:character <- next-duplex *before-cursor
+  deleted-cell:address:duplex-list:character <- next *before-cursor
   go-render? <- copy 0/false
   reply-unless deleted-cell
   currc:character <- get *deleted-cell, value:offset
-  remove-duplex deleted-cell
+  remove deleted-cell
   deleted-newline?:boolean <- equal currc, 10/newline
   go-render? <- copy 1/true
   reply-if deleted-newline?
   # wasn't a newline? render rest of line
-  curr:address:duplex-list:character <- next-duplex *before-cursor  # refresh after remove-duplex above
+  curr:address:duplex-list:character <- next *before-cursor  # refresh after remove above
   cursor-row:address:number <- get-address *editor, cursor-row:offset
   cursor-column:address:number <- get-address *editor, cursor-column:offset
   screen <- move-cursor screen, *cursor-row, *cursor-column
@@ -360,7 +360,7 @@ recipe delete-at-cursor editor:address:editor-data, screen:address:screen -> edi
     break-if at-newline?
     screen <- print-character screen, currc
     curr-column <- add curr-column, 1
-    curr <- next-duplex curr
+    curr <- next curr
     loop
   }
   # we're guaranteed not to be at the right margin
@@ -397,7 +397,7 @@ after <handle-special-key> [
     move-to-next-character?:boolean <- equal *k, 65514/right-arrow
     break-unless move-to-next-character?
     # if not at end of text
-    next-cursor:address:duplex-list:character <- next-duplex *before-cursor
+    next-cursor:address:duplex-list:character <- next *before-cursor
     break-unless next-cursor
     # scan to next character
     <move-cursor-begin>
@@ -440,7 +440,7 @@ recipe move-cursor-coordinates-right editor:address:editor-data, screen-height:n
     at-wrap?:boolean <- equal *cursor-column, wrap-column
     break-unless at-wrap?
     # and if next character isn't newline
-    next:address:duplex-list:character <- next-duplex before-cursor
+    next:address:duplex-list:character <- next before-cursor
     break-unless next
     next-character:character <- get *next, value:offset
     newline?:boolean <- equal next-character, 10/newline
@@ -674,7 +674,7 @@ after <handle-special-key> [
     break-unless move-to-previous-character?
     trace 10, [app], [left arrow]
     # if not at start of text (before-cursor at § sentinel)
-    prev:address:duplex-list:character <- prev-duplex *before-cursor
+    prev:address:duplex-list:character <- prev *before-cursor
     go-render? <- copy 0/false
     reply-unless prev
     <move-cursor-begin>
@@ -920,7 +920,7 @@ recipe move-to-previous-line editor:address:editor-data -> editor:address:editor
     {
       done?:boolean <- greater-or-equal *cursor-column, target-column
       break-if done?
-      curr:address:duplex-list:character <- next-duplex *before-cursor
+      curr:address:duplex-list:character <- next *before-cursor
       break-unless curr
       currc:character <- get *curr, value:offset
       at-newline?:boolean <- equal currc, 10/newline
@@ -1137,7 +1137,7 @@ recipe move-to-next-line editor:address:editor-data, screen-height:number -> edi
     {
       done?:boolean <- greater-or-equal *cursor-column, target-column
       break-if done?
-      curr:address:duplex-list:character <- next-duplex *before-cursor
+      curr:address:duplex-list:character <- next *before-cursor
       break-unless curr
       currc:character <- get *curr, value:offset
       at-newline?:boolean <- equal currc, 10/newline
@@ -1261,7 +1261,7 @@ recipe move-to-start-of-line editor:address:editor-data [
     prev:character <- get **before-cursor, value:offset
     at-start-of-line?:boolean <- equal prev, 10/newline
     break-if at-start-of-line?
-    *before-cursor <- prev-duplex *before-cursor
+    *before-cursor <- prev *before-cursor
     assert *before-cursor, [move-to-start-of-line tried to move before start of text]
     loop
   }
@@ -1422,7 +1422,7 @@ recipe move-to-end-of-line editor:address:editor-data [
   cursor-column:address:number <- get-address *editor, cursor-column:offset
   # while not at start of line, move 
   {
-    next:address:duplex-list:character <- next-duplex *before-cursor
+    next:address:duplex-list:character <- next *before-cursor
     break-unless next  # end of text
     nextc:character <- get *next, value:offset
     at-end-of-line?:boolean <- equal nextc, 10/newline
@@ -1552,20 +1552,20 @@ recipe delete-to-start-of-line editor:address:editor-data -> result:address:dupl
   init:address:duplex-list:character <- get *editor, data:offset
   before-cursor:address:address:duplex-list:character <- get-address *editor, before-cursor:offset
   start:address:duplex-list:character <- copy *before-cursor
-  end:address:duplex-list:character <- next-duplex *before-cursor
+  end:address:duplex-list:character <- next *before-cursor
   {
     at-start-of-text?:boolean <- equal start, init
     break-if at-start-of-text?
     curr:character <- get *start, value:offset
     at-start-of-line?:boolean <- equal curr, 10/newline
     break-if at-start-of-line?
-    start <- prev-duplex start
+    start <- prev start
     assert start, [delete-to-start-of-line tried to move before start of text]
     loop
   }
   # snip it out
-  result:address:duplex-list:character <- next-duplex start
-  remove-duplex-between start, end
+  result:address:duplex-list:character <- next start
+  remove-between start, end
   # adjust cursor
   *before-cursor <- copy start
   left:number <- get *editor, left:offset
@@ -1684,19 +1684,19 @@ recipe delete-to-end-of-line editor:address:editor-data -> result:address:duplex
   load-ingredients
   # compute range to delete
   start:address:duplex-list:character <- get *editor, before-cursor:offset
-  end:address:duplex-list:character <- next-duplex start
+  end:address:duplex-list:character <- next start
   {
     at-end-of-text?:boolean <- equal end, 0/null
     break-if at-end-of-text?
     curr:character <- get *end, value:offset
     at-end-of-line?:boolean <- equal curr, 10/newline
     break-if at-end-of-line?
-    end <- next-duplex end
+    end <- next end
     loop
   }
   # snip it out
-  result <- next-duplex start
-  remove-duplex-between start, end
+  result <- next start
+  remove-between start, end
 ]
 
 scenario editor-deletes-to-end-of-line-with-ctrl-k-2 [
@@ -1874,7 +1874,7 @@ recipe before-start-of-next-line original:address:duplex-list:character, max:num
     c:character <- get *curr, value:offset
     at-newline?:boolean <- equal c, 10/newline
     break-unless at-newline?
-    curr <- next-duplex curr
+    curr <- next curr
     count <- add count, 1
   }
   {
@@ -1884,7 +1884,7 @@ recipe before-start-of-next-line original:address:duplex-list:character, max:num
     c:character <- get *curr, value:offset
     at-newline?:boolean <- equal c, 10/newline
     break-if at-newline?
-    curr <- next-duplex curr
+    curr <- next curr
     count <- add count, 1
     loop
   }
@@ -2246,7 +2246,7 @@ recipe before-previous-line curr:address:duplex-list:character, editor:address:e
   {
     break-if len
     # empty line; just skip this newline
-    prev:address:duplex-list:character <- prev-duplex curr
+    prev:address:duplex-list:character <- prev curr
     reply-unless prev, curr
     reply prev
   }
@@ -2262,7 +2262,7 @@ recipe before-previous-line curr:address:duplex-list:character, editor:address:e
   {
     done?:boolean <- greater-or-equal count, max
     break-if done?
-    prev:address:duplex-list:character <- prev-duplex curr
+    prev:address:duplex-list:character <- prev curr
     break-unless prev
     curr <- copy prev
     count <- add count, 1
@@ -2648,13 +2648,13 @@ recipe page-down editor:address:editor-data -> editor:address:editor-data [
   reply-unless bottom-of-screen
   # if not, position cursor at final character
   before-cursor:address:address:duplex-list:character <- get-address *editor, before-cursor:offset
-  *before-cursor <- prev-duplex bottom-of-screen
+  *before-cursor <- prev bottom-of-screen
   # keep one line in common with previous page
   {
     last:character <- get **before-cursor, value:offset
     newline?:boolean <- equal last, 10/newline
     break-unless newline?:boolean
-    *before-cursor <- prev-duplex *before-cursor
+    *before-cursor <- prev *before-cursor
   }
   # move cursor and top-of-screen to start of that line
   move-to-start-of-line editor
diff --git a/edit/005-sandbox.mu b/edit/005-sandbox.mu
index 358d148c..79da2409 100644
--- a/edit/005-sandbox.mu
+++ b/edit/005-sandbox.mu
@@ -151,7 +151,7 @@ recipe run-sandboxes env:address:programming-environment-data, screen:address:sc
     *dest <- copy new-sandbox
     # clear sandbox editor
     init:address:address:duplex-list:character <- get-address *current-sandbox, data:offset
-    *init <- push-duplex 167/§, 0/tail
+    *init <- push 167/§, 0/tail
     top-of-screen:address:address:duplex-list:character <- get-address *current-sandbox, top-of-screen:offset
     *top-of-screen <- copy *init
   }
@@ -474,13 +474,13 @@ recipe editor-contents editor:address:editor-data -> result:address:array:charac
   curr:address:duplex-list:character <- get *editor, data:offset
   # skip § sentinel
   assert curr, [editor without data is illegal; must have at least a sentinel]
-  curr <- next-duplex curr
+  curr <- next curr
   reply-unless curr, 0
   {
     break-unless curr
     c:character <- get *curr, value:offset
     buffer-append buf, c
-    curr <- next-duplex curr
+    curr <- next curr
     loop
   }
   result <- buffer-to-array buf
diff --git a/edit/006-sandbox-edit.mu b/edit/006-sandbox-edit.mu
index bec144f4..ea95c6af 100644
--- a/edit/006-sandbox-edit.mu
+++ b/edit/006-sandbox-edit.mu
@@ -93,7 +93,7 @@ recipe empty-editor? editor:address:editor-data -> result:boolean [
   local-scope
   load-ingredients
   head:address:duplex-list:character <- get *editor, data:offset
-  first:address:duplex-list:character <- next-duplex head
+  first:address:duplex-list:character <- next head
   result <- not first
 ]
 
diff --git a/edit/011-editor-undo.mu b/edit/011-editor-undo.mu
index 655d30fb..0e423ff4 100644
--- a/edit/011-editor-undo.mu
+++ b/edit/011-editor-undo.mu
@@ -150,7 +150,7 @@ before <insert-character-end> [
     previous-coalesce-tag:number <- get *typing, tag:offset
     break-unless previous-coalesce-tag
     insert-until:address:address:duplex-list:character <- get-address *typing, insert-until:offset
-    *insert-until <- next-duplex *before-cursor
+    *insert-until <- next *before-cursor
     after-row:address:number <- get-address *typing, after-row:offset
     *after-row <- copy *cursor-row
     after-column:address:number <- get-address *typing, after-column:offset
@@ -160,8 +160,8 @@ before <insert-character-end> [
     break +done-adding-insert-operation:label
   }
   # if not, create a new operation
-  insert-from:address:duplex-list:character <- next-duplex cursor-before
-  insert-to:address:duplex-list:character <- next-duplex insert-from
+  insert-from:address:duplex-list:character <- next cursor-before
+  insert-to:address:duplex-list:character <- next insert-from
   op:address:operation <- new operation:type
   *op <- merge 0/insert-operation, save-row/before, save-column/before, top-before, *cursor-row/after, *cursor-column/after, top-after, insert-from, insert-to, 1/coalesce
   editor <- add-operation editor, op
@@ -178,8 +178,8 @@ after <insert-enter-begin> [
 before <insert-enter-end> [
   top-after:address:duplex-list:character <- get *editor, top-of-screen:offset
   # never coalesce
-  insert-from:address:duplex-list:character <- next-duplex cursor-before
-  insert-to:address:duplex-list:character <- next-duplex *before-cursor
+  insert-from:address:duplex-list:character <- next cursor-before
+  insert-to:address:duplex-list:character <- next *before-cursor
   op:address:operation <- new operation:type
   *op <- merge 0/insert-operation, cursor-row-before, cursor-column-before, top-before, *cursor-row/after, *cursor-column/after, top-after, insert-from, insert-to, 0/never-coalesce
   editor <- add-operation editor, op
@@ -206,8 +206,8 @@ after <handle-undo> [
     start:address:duplex-list:character <- get *typing, insert-from:offset
     end:address:duplex-list:character <- get *typing, insert-until:offset
     # assert cursor-row/cursor-column/top-of-screen match after-row/after-column/after-top-of-screen
-    *before-cursor <- prev-duplex start
-    remove-duplex-between *before-cursor, end
+    *before-cursor <- prev start
+    remove-between *before-cursor, end
     *cursor-row <- get *typing, before-row:offset
     *cursor-column <- get *typing, before-column:offset
     top:address:address:duplex-list:character <- get-address *editor, top-of-screen:offset
@@ -401,8 +401,8 @@ after <handle-redo> [
     typing:address:insert-operation <- maybe-convert *op, typing:variant
     break-unless typing
     insert-from:address:duplex-list:character <- get *typing, insert-from:offset  # ignore insert-to because it's already been spliced away
-    # assert insert-to matches next-duplex(*before-cursor)
-    insert-duplex-range *before-cursor, insert-from
+    # assert insert-to matches next(*before-cursor)
+    insert-range *before-cursor, insert-from
     # assert cursor-row/cursor-column/top-of-screen match after-row/after-column/after-top-of-screen
     *cursor-row <- get *typing, after-row:offset
     *cursor-column <- get *typing, after-column:offset
@@ -1608,7 +1608,7 @@ before <backspace-character-end> [
       delete-from:address:address:duplex-list:character <- get-address *deletion, delete-from:offset
       *delete-from <- copy *before-cursor
       backspaced-so-far:address:address:duplex-list:character <- get-address *deletion, deleted-text:offset
-      insert-duplex-range backspaced-cell, *backspaced-so-far
+      insert-range backspaced-cell, *backspaced-so-far
       *backspaced-so-far <- copy backspaced-cell
       after-row:address:number <- get-address *deletion, after-row:offset
       *after-row <- copy *cursor-row
@@ -1620,7 +1620,7 @@ before <backspace-character-end> [
     }
     # if not, create a new operation
     op:address:operation <- new operation:type
-    deleted-until:address:duplex-list:character <- next-duplex *before-cursor
+    deleted-until:address:duplex-list:character <- next *before-cursor
     *op <- merge 2/delete-operation, save-row/before, save-column/before, top-before, *cursor-row/after, *cursor-column/after, top-after, backspaced-cell/deleted, *before-cursor/delete-from, deleted-until, 1/coalesce-backspace
     editor <- add-operation editor, op
     +done-adding-backspace-operation
@@ -1635,8 +1635,8 @@ after <handle-undo> [
     anchor:address:duplex-list:character <- get *deletion, delete-from:offset
     break-unless anchor
     deleted:address:duplex-list:character <- get *deletion, deleted-text:offset
-    old-cursor:address:duplex-list:character <- last-duplex deleted
-    insert-duplex-range anchor, deleted
+    old-cursor:address:duplex-list:character <- last deleted
+    insert-range anchor, deleted
     # assert cursor-row/cursor-column/top-of-screen match after-row/after-column/after-top-of-screen
     *before-cursor <- copy old-cursor
     *cursor-row <- get *deletion, before-row:offset
@@ -1652,7 +1652,7 @@ after <handle-redo> [
     break-unless deletion
     start:address:duplex-list:character <- get *deletion, delete-from:offset
     end:address:duplex-list:character <- get *deletion, delete-until:offset
-    remove-duplex-between start, end
+    remove-between start, end
     # assert cursor-row/cursor-column/top-of-screen match after-row/after-column/after-top-of-screen
     *cursor-row <- get *deletion, after-row:offset
     *cursor-column <- get *deletion, after-column:offset
@@ -1828,9 +1828,9 @@ before <delete-character-end> [
       coalesce?:boolean <- equal previous-coalesce-tag, 2/coalesce-delete
       break-unless coalesce?
       delete-until:address:address:duplex-list:character <- get-address *deletion, delete-until:offset
-      *delete-until <- next-duplex *before-cursor
+      *delete-until <- next *before-cursor
       deleted-so-far:address:address:duplex-list:character <- get-address *deletion, deleted-text:offset
-      *deleted-so-far <- append-duplex *deleted-so-far, deleted-cell
+      *deleted-so-far <- append *deleted-so-far, deleted-cell
       after-row:address:number <- get-address *deletion, after-row:offset
       *after-row <- copy *cursor-row
       after-column:address:number <- get-address *deletion, after-column:offset
@@ -1841,7 +1841,7 @@ before <delete-character-end> [
     }
     # if not, create a new operation
     op:address:operation <- new operation:type
-    deleted-until:address:duplex-list:character <- next-duplex *before-cursor
+    deleted-until:address:duplex-list:character <- next *before-cursor
     *op <- merge 2/delete-operation, save-row/before, save-column/before, top-before, *cursor-row/after, *cursor-column/after, top-after, deleted-cell/deleted, *before-cursor/delete-from, deleted-until, 2/coalesce-delete
     editor <- add-operation editor, op
     +done-adding-delete-operation
@@ -1942,7 +1942,7 @@ before <delete-to-end-of-line-end> [
     top-after:address:duplex-list:character <- get *editor, top-of-screen:offset
     undo:address:address:list:address:operation <- get-address *editor, undo:offset
     op:address:operation <- new operation:type
-    deleted-until:address:duplex-list:character <- next-duplex *before-cursor
+    deleted-until:address:duplex-list:character <- next *before-cursor
     *op <- merge 2/delete-operation, save-row/before, save-column/before, top-before, *cursor-row/after, *cursor-column/after, top-after, deleted-cells/deleted, *before-cursor/delete-from, deleted-until, 0/never-coalesce
     editor <- add-operation editor, op
     +done-adding-delete-operation
@@ -2043,7 +2043,7 @@ before <delete-to-start-of-line-end> [
     top-after:address:duplex-list:character <- get *editor, top-of-screen:offset
     undo:address:address:list:address:operation <- get-address *editor, undo:offset
     op:address:operation <- new operation:type
-    deleted-until:address:duplex-list:character <- next-duplex *before-cursor
+    deleted-until:address:duplex-list:character <- next *before-cursor
     *op <- merge 2/delete-operation, save-row/before, save-column/before, top-before, *cursor-row/after, *cursor-column/after, top-after, deleted-cells/deleted, *before-cursor/delete-from, deleted-until, 0/never-coalesce
     editor <- add-operation editor, op
     +done-adding-delete-operation
diff --git a/sandbox/001-editor.mu b/sandbox/001-editor.mu
index 4b8da7a8..c74e6ac4 100644
--- a/sandbox/001-editor.mu
+++ b/sandbox/001-editor.mu
@@ -64,7 +64,7 @@ recipe new-editor s:address:array:character, screen:address:screen, left:number,
   x <- get-address *result, cursor-column:offset
   *x <- copy left
   init:address:address:duplex-list:character <- get-address *result, data:offset
-  *init <- push-duplex 167/§, 0/tail
+  *init <- push 167/§, 0/tail
   top-of-screen:address:address:duplex-list:character <- get-address *result, top-of-screen:offset
   *top-of-screen <- copy *init
   y:address:address:duplex-list:character <- get-address *result, before-cursor:offset
@@ -92,9 +92,9 @@ recipe insert-text editor:address:editor-data, text:address:array:character -> e
     done?:boolean <- greater-or-equal idx, len
     break-if done?
     c:character <- index *text, idx
-    insert-duplex c, curr
+    insert c, curr
     # next iter
-    curr <- next-duplex curr
+    curr <- next curr
     idx <- add idx, 1
     loop
   }
@@ -136,8 +136,8 @@ recipe render screen:address:screen, editor:address:editor-data -> last-row:numb
   right:number <- get *editor, right:offset
   # traversing editor
   curr:address:duplex-list:character <- get *editor, top-of-screen:offset
-  prev:address:duplex-list:character <- copy curr  # just in case curr becomes null and we can't compute prev-duplex
-  curr <- next-duplex curr
+  prev:address:duplex-list:character <- copy curr  # just in case curr becomes null and we can't compute prev
+  curr <- next curr
   # traversing screen
   +render-loop-initialization
   color:number <- copy 7/white
@@ -175,7 +175,7 @@ recipe render screen:address:screen, editor:address:editor-data -> last-row:numb
         left-of-cursor?:boolean <- lesser-than column, *cursor-column
         break-unless left-of-cursor?
         *cursor-column <- copy column
-        *before-cursor <- prev-duplex curr
+        *before-cursor <- prev curr
       }
       # clear rest of line in this window
       clear-line-delimited screen, column, right
@@ -183,8 +183,8 @@ recipe render screen:address:screen, editor:address:editor-data -> last-row:numb
       row <- add row, 1
       column <- copy left
       screen <- move-cursor screen, row, column
-      curr <- next-duplex curr
-      prev <- next-duplex prev
+      curr <- next curr
+      prev <- next prev
       loop +next-character:label
     }
     {
@@ -201,8 +201,8 @@ recipe render screen:address:screen, editor:address:editor-data -> last-row:numb
       loop +next-character:label
     }
     print-character screen, c, color
-    curr <- next-duplex curr
-    prev <- next-duplex prev
+    curr <- next curr
+    prev <- next prev
     column <- add column, 1
     loop
   }
diff --git a/sandbox/002-typing.mu b/sandbox/002-typing.mu
index e766926a..bc47e2d8 100644
--- a/sandbox/002-typing.mu
+++ b/sandbox/002-typing.mu
@@ -79,8 +79,8 @@ recipe snap-cursor screen:address:screen, editor:address:editor-data, target-row
   screen-height:number <- screen-height screen
   # count newlines until screen row
   curr:address:duplex-list:character <- get *editor, top-of-screen:offset
-  prev:address:duplex-list:character <- copy curr  # just in case curr becomes null and we can't compute prev-duplex
-  curr <- next-duplex curr
+  prev:address:duplex-list:character <- copy curr  # just in case curr becomes null and we can't compute prev
+  curr <- next curr
   row:number <- copy 1/top
   column:number <- copy left
   cursor-row:address:number <- get-address *editor, cursor-row:offset
@@ -120,8 +120,8 @@ recipe snap-cursor screen:address:screen, editor:address:editor-data, target-row
       # skip to next line
       row <- add row, 1
       column <- copy left
-      curr <- next-duplex curr
-      prev <- next-duplex prev
+      curr <- next curr
+      prev <- next prev
       loop +next-character:label
     }
     {
@@ -134,8 +134,8 @@ recipe snap-cursor screen:address:screen, editor:address:editor-data, target-row
       # don't increment curr/prev
       loop +next-character:label
     }
-    curr <- next-duplex curr
-    prev <- next-duplex prev
+    curr <- next curr
+    prev <- next prev
     column <- add column, 1
     loop
   }
@@ -199,8 +199,8 @@ recipe insert-at-cursor editor:address:editor-data, c:character, screen:address:
   local-scope
   load-ingredients
   before-cursor:address:address:duplex-list:character <- get-address *editor, before-cursor:offset
-  insert-duplex c, *before-cursor
-  *before-cursor <- next-duplex *before-cursor
+  insert c, *before-cursor
+  *before-cursor <- next *before-cursor
   cursor-row:address:number <- get-address *editor, cursor-row:offset
   cursor-column:address:number <- get-address *editor, cursor-column:offset
   left:number <- get *editor, left:offset
@@ -213,7 +213,7 @@ recipe insert-at-cursor editor:address:editor-data, c:character, screen:address:
   <insert-character-special-case>
   # but mostly we'll just move the cursor right
   *cursor-column <- add *cursor-column, 1
-  next:address:duplex-list:character <- next-duplex *before-cursor
+  next:address:duplex-list:character <- next *before-cursor
   {
     # at end of all text? no need to scroll? just print the character and leave
     at-end?:boolean <- equal next, 0/null
@@ -248,7 +248,7 @@ recipe insert-at-cursor editor:address:editor-data, c:character, screen:address:
       break-if at-newline?
       print-character screen, currc
       curr-column <- add curr-column, 1
-      curr <- next-duplex curr
+      curr <- next curr
       loop
     }
     go-render? <- copy 0/false
@@ -832,8 +832,8 @@ recipe insert-new-line-and-indent editor:address:editor-data, screen:address:scr
   right:number <- get *editor, right:offset
   screen-height:number <- screen-height screen
   # insert newline
-  insert-duplex 10/newline, *before-cursor
-  *before-cursor <- next-duplex *before-cursor
+  insert 10/newline, *before-cursor
+  *before-cursor <- next *before-cursor
   *cursor-row <- add *cursor-row, 1
   *cursor-column <- copy left
   # maybe scroll
@@ -848,7 +848,7 @@ recipe insert-new-line-and-indent editor:address:editor-data, screen:address:scr
   indent?:boolean <- get *editor, indent?:offset
   reply-unless indent?
   d:address:duplex-list:character <- get *editor, data:offset
-  end-of-previous-line:address:duplex-list:character <- prev-duplex *before-cursor
+  end-of-previous-line:address:duplex-list:character <- prev *before-cursor
   indent:number <- line-indent end-of-previous-line, d
   i:number <- copy 0
   {
@@ -870,7 +870,7 @@ recipe line-indent curr:address:duplex-list:character, start:address:duplex-list
   at-start?:boolean <- equal curr, start
   reply-if at-start?
   {
-    curr <- prev-duplex curr
+    curr <- prev curr
     break-unless curr
     at-start?:boolean <- equal curr, start
     break-if at-start?
diff --git a/sandbox/003-shortcuts.mu b/sandbox/003-shortcuts.mu
index f4c480d3..9c46c927 100644
--- a/sandbox/003-shortcuts.mu
+++ b/sandbox/003-shortcuts.mu
@@ -85,14 +85,14 @@ recipe delete-before-cursor editor:address:editor-data, screen:address:screen ->
   load-ingredients
   before-cursor:address:address:duplex-list:character <- get-address *editor, before-cursor:offset
   # if at start of text (before-cursor at § sentinel), return
-  prev:address:duplex-list:character <- prev-duplex *before-cursor
+  prev:address:duplex-list:character <- prev *before-cursor
   go-render?, backspaced-cell <- copy 0/no-more-render, 0/nothing-deleted
   reply-unless prev
   trace 10, [app], [delete-before-cursor]
   original-row:number <- get *editor, cursor-row:offset
   editor, scroll?:boolean <- move-cursor-coordinates-left editor
   backspaced-cell:address:duplex-list:character <- copy *before-cursor
-  remove-duplex *before-cursor  # will also neatly trim next/prev pointers in backspaced-cell/*before-cursor
+  remove *before-cursor  # will also neatly trim next/prev pointers in backspaced-cell/*before-cursor
   *before-cursor <- copy prev
   go-render? <- copy 1/true
   reply-if scroll?
@@ -105,7 +105,7 @@ recipe delete-before-cursor editor:address:editor-data, screen:address:screen ->
   reply-unless same-row?
   left:number <- get *editor, left:offset
   right:number <- get *editor, right:offset
-  curr:address:duplex-list:character <- next-duplex *before-cursor
+  curr:address:duplex-list:character <- next *before-cursor
   screen <- move-cursor screen, cursor-row, cursor-column
   curr-column:number <- copy cursor-column
   {
@@ -120,7 +120,7 @@ recipe delete-before-cursor editor:address:editor-data, screen:address:screen ->
     break-if at-newline?
     screen <- print-character screen, currc
     curr-column <- add curr-column, 1
-    curr <- next-duplex curr
+    curr <- next curr
     loop
   }
   # we're guaranteed not to be at the right margin
@@ -184,7 +184,7 @@ recipe previous-line-length curr:address:duplex-list:character, start:address:du
   at-start?:boolean <- equal curr, start
   reply-if at-start?
   {
-    curr <- prev-duplex curr
+    curr <- prev curr
     break-unless curr
     at-start?:boolean <- equal curr, start
     break-if at-start?
@@ -333,16 +333,16 @@ recipe delete-at-cursor editor:address:editor-data, screen:address:screen -> edi
   local-scope
   load-ingredients
   before-cursor:address:address:duplex-list:character <- get-address *editor, before-cursor:offset
-  deleted-cell:address:duplex-list:character <- next-duplex *before-cursor
+  deleted-cell:address:duplex-list:character <- next *before-cursor
   go-render? <- copy 0/false
   reply-unless deleted-cell
   currc:character <- get *deleted-cell, value:offset
-  remove-duplex deleted-cell
+  remove deleted-cell
   deleted-newline?:boolean <- equal currc, 10/newline
   go-render? <- copy 1/true
   reply-if deleted-newline?
   # wasn't a newline? render rest of line
-  curr:address:duplex-list:character <- next-duplex *before-cursor  # refresh after remove-duplex above
+  curr:address:duplex-list:character <- next *before-cursor  # refresh after remove above
   cursor-row:address:number <- get-address *editor, cursor-row:offset
   cursor-column:address:number <- get-address *editor, cursor-column:offset
   screen <- move-cursor screen, *cursor-row, *cursor-column
@@ -360,7 +360,7 @@ recipe delete-at-cursor editor:address:editor-data, screen:address:screen -> edi
     break-if at-newline?
     screen <- print-character screen, currc
     curr-column <- add curr-column, 1
-    curr <- next-duplex curr
+    curr <- next curr
     loop
   }
   # we're guaranteed not to be at the right margin
@@ -397,7 +397,7 @@ after <handle-special-key> [
     move-to-next-character?:boolean <- equal *k, 65514/right-arrow
     break-unless move-to-next-character?
     # if not at end of text
-    next-cursor:address:duplex-list:character <- next-duplex *before-cursor
+    next-cursor:address:duplex-list:character <- next *before-cursor
     break-unless next-cursor
     # scan to next character
     <move-cursor-begin>
@@ -440,7 +440,7 @@ recipe move-cursor-coordinates-right editor:address:editor-data, screen-height:n
     at-wrap?:boolean <- equal *cursor-column, wrap-column
     break-unless at-wrap?
     # and if next character isn't newline
-    next:address:duplex-list:character <- next-duplex before-cursor
+    next:address:duplex-list:character <- next before-cursor
     break-unless next
     next-character:character <- get *next, value:offset
     newline?:boolean <- equal next-character, 10/newline
@@ -674,7 +674,7 @@ after <handle-special-key> [
     break-unless move-to-previous-character?
     trace 10, [app], [left arrow]
     # if not at start of text (before-cursor at § sentinel)
-    prev:address:duplex-list:character <- prev-duplex *before-cursor
+    prev:address:duplex-list:character <- prev *before-cursor
     go-render? <- copy 0/false
     reply-unless prev
     <move-cursor-begin>
@@ -920,7 +920,7 @@ recipe move-to-previous-line editor:address:editor-data -> editor:address:editor
     {
       done?:boolean <- greater-or-equal *cursor-column, target-column
       break-if done?
-      curr:address:duplex-list:character <- next-duplex *before-cursor
+      curr:address:duplex-list:character <- next *before-cursor
       break-unless curr
       currc:character <- get *curr, value:offset
       at-newline?:boolean <- equal currc, 10/newline
@@ -1137,7 +1137,7 @@ recipe move-to-next-line editor:address:editor-data, screen-height:number -> edi
     {
       done?:boolean <- greater-or-equal *cursor-column, target-column
       break-if done?
-      curr:address:duplex-list:character <- next-duplex *before-cursor
+      curr:address:duplex-list:character <- next *before-cursor
       break-unless curr
       currc:character <- get *curr, value:offset
       at-newline?:boolean <- equal currc, 10/newline
@@ -1261,7 +1261,7 @@ recipe move-to-start-of-line editor:address:editor-data [
     prev:character <- get **before-cursor, value:offset
     at-start-of-line?:boolean <- equal prev, 10/newline
     break-if at-start-of-line?
-    *before-cursor <- prev-duplex *before-cursor
+    *before-cursor <- prev *before-cursor
     assert *before-cursor, [move-to-start-of-line tried to move before start of text]
     loop
   }
@@ -1422,7 +1422,7 @@ recipe move-to-end-of-line editor:address:editor-data [
   cursor-column:address:number <- get-address *editor, cursor-column:offset
   # while not at start of line, move 
   {
-    next:address:duplex-list:character <- next-duplex *before-cursor
+    next:address:duplex-list:character <- next *before-cursor
     break-unless next  # end of text
     nextc:character <- get *next, value:offset
     at-end-of-line?:boolean <- equal nextc, 10/newline
@@ -1552,20 +1552,20 @@ recipe delete-to-start-of-line editor:address:editor-data -> result:address:dupl
   init:address:duplex-list:character <- get *editor, data:offset
   before-cursor:address:address:duplex-list:character <- get-address *editor, before-cursor:offset
   start:address:duplex-list:character <- copy *before-cursor
-  end:address:duplex-list:character <- next-duplex *before-cursor
+  end:address:duplex-list:character <- next *before-cursor
   {
     at-start-of-text?:boolean <- equal start, init
     break-if at-start-of-text?
     curr:character <- get *start, value:offset
     at-start-of-line?:boolean <- equal curr, 10/newline
     break-if at-start-of-line?
-    start <- prev-duplex start
+    start <- prev start
     assert start, [delete-to-start-of-line tried to move before start of text]
     loop
   }
   # snip it out
-  result:address:duplex-list:character <- next-duplex start
-  remove-duplex-between start, end
+  result:address:duplex-list:character <- next start
+  remove-between start, end
   # adjust cursor
   *before-cursor <- copy start
   left:number <- get *editor, left:offset
@@ -1684,19 +1684,19 @@ recipe delete-to-end-of-line editor:address:editor-data -> result:address:duplex
   load-ingredients
   # compute range to delete
   start:address:duplex-list:character <- get *editor, before-cursor:offset
-  end:address:duplex-list:character <- next-duplex start
+  end:address:duplex-list:character <- next start
   {
     at-end-of-text?:boolean <- equal end, 0/null
     break-if at-end-of-text?
     curr:character <- get *end, value:offset
     at-end-of-line?:boolean <- equal curr, 10/newline
     break-if at-end-of-line?
-    end <- next-duplex end
+    end <- next end
     loop
   }
   # snip it out
-  result <- next-duplex start
-  remove-duplex-between start, end
+  result <- next start
+  remove-between start, end
 ]
 
 scenario editor-deletes-to-end-of-line-with-ctrl-k-2 [
@@ -1874,7 +1874,7 @@ recipe before-start-of-next-line original:address:duplex-list:character, max:num
     c:character <- get *curr, value:offset
     at-newline?:boolean <- equal c, 10/newline
     break-unless at-newline?
-    curr <- next-duplex curr
+    curr <- next curr
     count <- add count, 1
   }
   {
@@ -1884,7 +1884,7 @@ recipe before-start-of-next-line original:address:duplex-list:character, max:num
     c:character <- get *curr, value:offset
     at-newline?:boolean <- equal c, 10/newline
     break-if at-newline?
-    curr <- next-duplex curr
+    curr <- next curr
     count <- add count, 1
     loop
   }
@@ -2246,7 +2246,7 @@ recipe before-previous-line curr:address:duplex-list:character, editor:address:e
   {
     break-if len
     # empty line; just skip this newline
-    prev:address:duplex-list:character <- prev-duplex curr
+    prev:address:duplex-list:character <- prev curr
     reply-unless prev, curr
     reply prev
   }
@@ -2262,7 +2262,7 @@ recipe before-previous-line curr:address:duplex-list:character, editor:address:e
   {
     done?:boolean <- greater-or-equal count, max
     break-if done?
-    prev:address:duplex-list:character <- prev-duplex curr
+    prev:address:duplex-list:character <- prev curr
     break-unless prev
     curr <- copy prev
     count <- add count, 1
@@ -2648,13 +2648,13 @@ recipe page-down editor:address:editor-data -> editor:address:editor-data [
   reply-unless bottom-of-screen
   # if not, position cursor at final character
   before-cursor:address:address:duplex-list:character <- get-address *editor, before-cursor:offset
-  *before-cursor <- prev-duplex bottom-of-screen
+  *before-cursor <- prev bottom-of-screen
   # keep one line in common with previous page
   {
     last:character <- get **before-cursor, value:offset
     newline?:boolean <- equal last, 10/newline
     break-unless newline?:boolean
-    *before-cursor <- prev-duplex *before-cursor
+    *before-cursor <- prev *before-cursor
   }
   # move cursor and top-of-screen to start of that line
   move-to-start-of-line editor
diff --git a/sandbox/005-sandbox.mu b/sandbox/005-sandbox.mu
index bbd3f8f8..083dcc1c 100644
--- a/sandbox/005-sandbox.mu
+++ b/sandbox/005-sandbox.mu
@@ -136,7 +136,7 @@ recipe run-sandboxes env:address:programming-environment-data, screen:address:sc
     *dest <- copy new-sandbox
     # clear sandbox editor
     init:address:address:duplex-list:character <- get-address *current-sandbox, data:offset
-    *init <- push-duplex 167/§, 0/tail
+    *init <- push 167/§, 0/tail
     top-of-screen:address:address:duplex-list:character <- get-address *current-sandbox, top-of-screen:offset
     *top-of-screen <- copy *init
   }
@@ -406,13 +406,13 @@ recipe editor-contents editor:address:editor-data -> result:address:array:charac
   curr:address:duplex-list:character <- get *editor, data:offset
   # skip § sentinel
   assert curr, [editor without data is illegal; must have at least a sentinel]
-  curr <- next-duplex curr
+  curr <- next curr
   reply-unless curr, 0
   {
     break-unless curr
     c:character <- get *curr, value:offset
     buffer-append buf, c
-    curr <- next-duplex curr
+    curr <- next curr
     loop
   }
   result <- buffer-to-array buf
diff --git a/sandbox/006-sandbox-edit.mu b/sandbox/006-sandbox-edit.mu
index 778d30c0..e021b961 100644
--- a/sandbox/006-sandbox-edit.mu
+++ b/sandbox/006-sandbox-edit.mu
@@ -94,7 +94,7 @@ recipe empty-editor? editor:address:editor-data -> result:boolean [
   local-scope
   load-ingredients
   head:address:duplex-list:character <- get *editor, data:offset
-  first:address:duplex-list:character <- next-duplex head
+  first:address:duplex-list:character <- next head
   result <- not first
 ]
 
diff --git a/sandbox/011-editor-undo.mu b/sandbox/011-editor-undo.mu
index 655d30fb..0e423ff4 100644
--- a/sandbox/011-editor-undo.mu
+++ b/sandbox/011-editor-undo.mu
@@ -150,7 +150,7 @@ before <insert-character-end> [
     previous-coalesce-tag:number <- get *typing, tag:offset
     break-unless previous-coalesce-tag
     insert-until:address:address:duplex-list:character <- get-address *typing, insert-until:offset
-    *insert-until <- next-duplex *before-cursor
+    *insert-until <- next *before-cursor
     after-row:address:number <- get-address *typing, after-row:offset
     *after-row <- copy *cursor-row
     after-column:address:number <- get-address *typing, after-column:offset
@@ -160,8 +160,8 @@ before <insert-character-end> [
     break +done-adding-insert-operation:label
   }
   # if not, create a new operation
-  insert-from:address:duplex-list:character <- next-duplex cursor-before
-  insert-to:address:duplex-list:character <- next-duplex insert-from
+  insert-from:address:duplex-list:character <- next cursor-before
+  insert-to:address:duplex-list:character <- next insert-from
   op:address:operation <- new operation:type
   *op <- merge 0/insert-operation, save-row/before, save-column/before, top-before, *cursor-row/after, *cursor-column/after, top-after, insert-from, insert-to, 1/coalesce
   editor <- add-operation editor, op
@@ -178,8 +178,8 @@ after <insert-enter-begin> [
 before <insert-enter-end> [
   top-after:address:duplex-list:character <- get *editor, top-of-screen:offset
   # never coalesce
-  insert-from:address:duplex-list:character <- next-duplex cursor-before
-  insert-to:address:duplex-list:character <- next-duplex *before-cursor
+  insert-from:address:duplex-list:character <- next cursor-before
+  insert-to:address:duplex-list:character <- next *before-cursor
   op:address:operation <- new operation:type
   *op <- merge 0/insert-operation, cursor-row-before, cursor-column-before, top-before, *cursor-row/after, *cursor-column/after, top-after, insert-from, insert-to, 0/never-coalesce
   editor <- add-operation editor, op
@@ -206,8 +206,8 @@ after <handle-undo> [
     start:address:duplex-list:character <- get *typing, insert-from:offset
     end:address:duplex-list:character <- get *typing, insert-until:offset
     # assert cursor-row/cursor-column/top-of-screen match after-row/after-column/after-top-of-screen
-    *before-cursor <- prev-duplex start
-    remove-duplex-between *before-cursor, end
+    *before-cursor <- prev start
+    remove-between *before-cursor, end
     *cursor-row <- get *typing, before-row:offset
     *cursor-column <- get *typing, before-column:offset
     top:address:address:duplex-list:character <- get-address *editor, top-of-screen:offset
@@ -401,8 +401,8 @@ after <handle-redo> [
     typing:address:insert-operation <- maybe-convert *op, typing:variant
     break-unless typing
     insert-from:address:duplex-list:character <- get *typing, insert-from:offset  # ignore insert-to because it's already been spliced away
-    # assert insert-to matches next-duplex(*before-cursor)
-    insert-duplex-range *before-cursor, insert-from
+    # assert insert-to matches next(*before-cursor)
+    insert-range *before-cursor, insert-from
     # assert cursor-row/cursor-column/top-of-screen match after-row/after-column/after-top-of-screen
     *cursor-row <- get *typing, after-row:offset
     *cursor-column <- get *typing, after-column:offset
@@ -1608,7 +1608,7 @@ before <backspace-character-end> [
       delete-from:address:address:duplex-list:character <- get-address *deletion, delete-from:offset
       *delete-from <- copy *before-cursor
       backspaced-so-far:address:address:duplex-list:character <- get-address *deletion, deleted-text:offset
-      insert-duplex-range backspaced-cell, *backspaced-so-far
+      insert-range backspaced-cell, *backspaced-so-far
       *backspaced-so-far <- copy backspaced-cell
       after-row:address:number <- get-address *deletion, after-row:offset
       *after-row <- copy *cursor-row
@@ -1620,7 +1620,7 @@ before <backspace-character-end> [
     }
     # if not, create a new operation
     op:address:operation <- new operation:type
-    deleted-until:address:duplex-list:character <- next-duplex *before-cursor
+    deleted-until:address:duplex-list:character <- next *before-cursor
     *op <- merge 2/delete-operation, save-row/before, save-column/before, top-before, *cursor-row/after, *cursor-column/after, top-after, backspaced-cell/deleted, *before-cursor/delete-from, deleted-until, 1/coalesce-backspace
     editor <- add-operation editor, op
     +done-adding-backspace-operation
@@ -1635,8 +1635,8 @@ after <handle-undo> [
     anchor:address:duplex-list:character <- get *deletion, delete-from:offset
     break-unless anchor
     deleted:address:duplex-list:character <- get *deletion, deleted-text:offset
-    old-cursor:address:duplex-list:character <- last-duplex deleted
-    insert-duplex-range anchor, deleted
+    old-cursor:address:duplex-list:character <- last deleted
+    insert-range anchor, deleted
     # assert cursor-row/cursor-column/top-of-screen match after-row/after-column/after-top-of-screen
     *before-cursor <- copy old-cursor
     *cursor-row <- get *deletion, before-row:offset
@@ -1652,7 +1652,7 @@ after <handle-redo> [
     break-unless deletion
     start:address:duplex-list:character <- get *deletion, delete-from:offset
     end:address:duplex-list:character <- get *deletion, delete-until:offset
-    remove-duplex-between start, end
+    remove-between start, end
     # assert cursor-row/cursor-column/top-of-screen match after-row/after-column/after-top-of-screen
     *cursor-row <- get *deletion, after-row:offset
     *cursor-column <- get *deletion, after-column:offset
@@ -1828,9 +1828,9 @@ before <delete-character-end> [
       coalesce?:boolean <- equal previous-coalesce-tag, 2/coalesce-delete
       break-unless coalesce?
       delete-until:address:address:duplex-list:character <- get-address *deletion, delete-until:offset
-      *delete-until <- next-duplex *before-cursor
+      *delete-until <- next *before-cursor
       deleted-so-far:address:address:duplex-list:character <- get-address *deletion, deleted-text:offset
-      *deleted-so-far <- append-duplex *deleted-so-far, deleted-cell
+      *deleted-so-far <- append *deleted-so-far, deleted-cell
       after-row:address:number <- get-address *deletion, after-row:offset
       *after-row <- copy *cursor-row
       after-column:address:number <- get-address *deletion, after-column:offset
@@ -1841,7 +1841,7 @@ before <delete-character-end> [
     }
     # if not, create a new operation
     op:address:operation <- new operation:type
-    deleted-until:address:duplex-list:character <- next-duplex *before-cursor
+    deleted-until:address:duplex-list:character <- next *before-cursor
     *op <- merge 2/delete-operation, save-row/before, save-column/before, top-before, *cursor-row/after, *cursor-column/after, top-after, deleted-cell/deleted, *before-cursor/delete-from, deleted-until, 2/coalesce-delete
     editor <- add-operation editor, op
     +done-adding-delete-operation
@@ -1942,7 +1942,7 @@ before <delete-to-end-of-line-end> [
     top-after:address:duplex-list:character <- get *editor, top-of-screen:offset
     undo:address:address:list:address:operation <- get-address *editor, undo:offset
     op:address:operation <- new operation:type
-    deleted-until:address:duplex-list:character <- next-duplex *before-cursor
+    deleted-until:address:duplex-list:character <- next *before-cursor
     *op <- merge 2/delete-operation, save-row/before, save-column/before, top-before, *cursor-row/after, *cursor-column/after, top-after, deleted-cells/deleted, *before-cursor/delete-from, deleted-until, 0/never-coalesce
     editor <- add-operation editor, op
     +done-adding-delete-operation
@@ -2043,7 +2043,7 @@ before <delete-to-start-of-line-end> [
     top-after:address:duplex-list:character <- get *editor, top-of-screen:offset
     undo:address:address:list:address:operation <- get-address *editor, undo:offset
     op:address:operation <- new operation:type
-    deleted-until:address:duplex-list:character <- next-duplex *before-cursor
+    deleted-until:address:duplex-list:character <- next *before-cursor
     *op <- merge 2/delete-operation, save-row/before, save-column/before, top-before, *cursor-row/after, *cursor-column/after, top-after, deleted-cells/deleted, *before-cursor/delete-from, deleted-until, 0/never-coalesce
     editor <- add-operation editor, op
     +done-adding-delete-operation