diff --git a/examples/dns.c b/examples/dns.c
index c8e3fafe76ee8e71094d5ca34b2d540288f39785..c1268127af7648a18fd85be278c648c98bab6c46 100644
--- a/examples/dns.c
+++ b/examples/dns.c
@@ -143,7 +143,7 @@ const HParsedToken* act_question(const HParseResult *p) {
   q->qname.qlen   = fields[0]->seq->used;
   q->qname.labels = h_arena_malloc(p->arena, sizeof(dns_label_t)*q->qname.qlen);
   for(size_t i=0; i<fields[0]->seq->used; i++) {
-    q->qname.labels[i] = *H_SEQ_INDEX(dns_label_t, fields[0], i);
+    q->qname.labels[i] = *H_INDEX(dns_label_t, fields[0], i);
   }
 
   q->qtype  = fields[1]->uint;
@@ -165,7 +165,7 @@ const HParsedToken* act_message(const HParseResult *p) {
   struct dns_question *questions = h_arena_malloc(p->arena,
 						  sizeof(struct dns_question)*(header->question_count));
   for (size_t i=0; i<header->question_count; ++i) {
-    questions[i] = *H_SEQ_INDEX(dns_question_t, qs, i);
+    questions[i] = *H_INDEX(dns_question_t, qs, i);
   }
   msg->questions = questions;
 
@@ -174,7 +174,7 @@ const HParsedToken* act_message(const HParseResult *p) {
   struct dns_rr *answers = h_arena_malloc(p->arena,
 					  sizeof(struct dns_rr)*(header->answer_count));
   for (size_t i=0; i<header->answer_count; ++i) {
-    answers[i] = *H_SEQ_INDEX(dns_rr_t, rrs, i);
+    answers[i] = *H_INDEX(dns_rr_t, rrs, i);
   }
   msg->answers = answers;
 
@@ -182,7 +182,7 @@ const HParsedToken* act_message(const HParseResult *p) {
   struct dns_rr *authority = h_arena_malloc(p->arena,
 					  sizeof(struct dns_rr)*(header->authority_count));
   for (size_t i=0, j=header->answer_count; i<header->authority_count; ++i, ++j) {
-    authority[i] = *H_SEQ_INDEX(dns_rr_t, rrs, j);
+    authority[i] = *H_INDEX(dns_rr_t, rrs, j);
   }
   msg->authority = authority;
 
@@ -190,7 +190,7 @@ const HParsedToken* act_message(const HParseResult *p) {
   struct dns_rr *additional = h_arena_malloc(p->arena,
 					     sizeof(struct dns_rr)*(header->additional_count));
   for (size_t i=0, j=header->answer_count+header->authority_count; i<header->additional_count; ++i, ++j) {
-    additional[i] = *H_SEQ_INDEX(dns_rr_t, rrs, j);
+    additional[i] = *H_INDEX(dns_rr_t, rrs, j);
   }
   msg->additional = additional;
 
diff --git a/examples/glue.c b/examples/glue.c
index 4cc85d089046cd759617d6b39f4d822c609b7e30..6fe3392d3aec0ca152bef334ac1514f47da985d4 100644
--- a/examples/glue.c
+++ b/examples/glue.c
@@ -57,7 +57,7 @@ const HParsedToken *h_seq_flatten(HArena *arena, const HParsedToken *p)
   case TT_SEQUENCE:
     // Flatten and append all.
     for(size_t i; i<p->seq->used; i++) {
-	  h_seq_append(ret, h_seq_flatten(arena, h_seq_index_token(p, i)));
+	  h_seq_append(ret, h_seq_flatten(arena, h_seq_index(p, i)));
 	}
 	break;
   default:
@@ -126,16 +126,16 @@ HParsedToken *h_carray_index(const HCountedArray *a, size_t i)
   return a->elements[i];
 }
 
-HParsedToken *h_seq_index_token(const HParsedToken *p, size_t i)
+HParsedToken *h_seq_index(const HParsedToken *p, size_t i)
 {
   assert(p != NULL);
   assert(p->token_type == TT_SEQUENCE);
   return h_carray_index(p->seq, i);
 }
 
-void *h_seq_index(HTokenType type, const HParsedToken *p, size_t i)
+void *h_seq_index_user(HTokenType type, const HParsedToken *p, size_t i)
 {
-  HParsedToken *elem = h_seq_index_token(p, i);
+  HParsedToken *elem = h_seq_index(p, i);
   assert(elem->token_type == (HTokenType)type);
   return elem->user;
 }
diff --git a/examples/glue.h b/examples/glue.h
index 9b11315f7f60b766a8c3f68dbd08f1b487a47d0c..4712cfc5a938e1154a43c0411f7ed277990d36dd 100644
--- a/examples/glue.h
+++ b/examples/glue.h
@@ -44,8 +44,7 @@ const HParsedToken *h_act_flatten(const HParseResult *p);
 //
 
 // Standard short-hand for arena-allocating a variable in a semantic action.
-#define H_ALLOC(TYP) \
-  ((TYP *) h_arena_malloc(p->arena, sizeof(TYP)))
+#define H_ALLOC(TYP)  ((TYP *) h_arena_malloc(p->arena, sizeof(TYP)))
 
 // Token constructors...
 
@@ -62,28 +61,49 @@ HParsedToken *h_make_uint(HArena *arena, uint64_t val);
 #define H_MAKE_SINT(VAL)  h_make_sint(p->arena, VAL)
 #define H_MAKE_UINT(VAL)  h_make_uint(p->arena, VAL)
 
+// Extract type-specific value back from HParsedTokens...
+
+void *         h_cast      (HTokenType type, const HParsedToken *p);
+HCountedArray *h_cast_seq  (const HParsedToken *p);
+HBytes         h_cast_bytes(const HParsedToken *p);
+int64_t        h_cast_sint (const HParsedToken *p);
+uint64_t       h_cast_uint (const HParsedToken *p);
+
+// Standard short-hand to cast to a user type.
+#define H_CAST(TYP, TOK)  ((TYP *) h_cast(TT_ ## TYP, TOK))
+
 // Sequence access...
 
 // Access a sequence element by index.
-HParsedToken *h_seq_index_token(const HParsedToken *p, size_t i);
+HParsedToken * h_seq_index(const HParsedToken *p, size_t i);
 
-// Access a user-type element of a sequence by index.
-#define H_SEQ_INDEX(TYP, SEQ, IDX) \
-  ((TYP *) h_seq_index(TT_ ## TYP, SEQ, IDX))
+// Convenience functions combining index access and h_cast_*.
+HCountedArray *h_seq_index_seq  (const HParsedToken *p, size_t i);
+HBytes         h_seq_index_bytes(const HParsedToken *p, size_t i);
+int64_t        h_seq_index_sint (const HParsedToken *p, size_t i);
+uint64_t       h_seq_index_uint (const HParsedToken *p, size_t i);
+void *         h_seq_index_user (HTokenType type, const HParsedToken *p, size_t i);
 
-// Standard short-hand to access a user-type field on a sequence token.
-#define H_FIELD(TYP, IDX)  H_SEQ_INDEX(TYP, p->ast, IDX)
+// Standard short-hand to access and cast a user-type sequence element.
+#define H_INDEX(TYP, SEQ, IDX) \
+  ((TYP *) h_seq_index_user(TT_ ## TYP, SEQ, IDX))
 
-// Lower-level helper for H_SEQ_INDEX.
-void *h_seq_index(HTokenType type, const HParsedToken *p, size_t i);
+// Standard short-hand to access and cast a user-type field on a sequence token.
+#define H_FIELD(TYP, IDX)  H_INDEX(TYP, p->ast, IDX)
+
+// Lower-level helper for h_seq_index.
 HParsedToken *h_carray_index(const HCountedArray *a, size_t i); // XXX -> internal
 
 // Sequence modification...
 
-// Append elements to a sequence.
+// Add elements to a sequence.
+void h_seq_cons(const HParsedToken *x, HParsedToken *xs);     // prepend one
 void h_seq_snoc(HParsedToken *xs, const HParsedToken *x);     // append one
+void h_seq_prepend(const HParsedToken *xs, HParsedToken *ys); // prepend many
 void h_seq_append(HParsedToken *xs, const HParsedToken *ys);  // append many
 
+// XXX TODO: Remove elements from a sequence.
+
 // Flatten nested sequences into one.
 const HParsedToken *h_seq_flatten(HArena *arena, const HParsedToken *p);
 
diff --git a/src/hammer.h b/src/hammer.h
index 5a0c6257585686deaf13673fc6fa412a11068b9f..7ef2883a7471744813a814fb87bdce08218be1a9 100644
--- a/src/hammer.h
+++ b/src/hammer.h
@@ -54,13 +54,15 @@ typedef struct HCountedArray_ {
   struct HParsedToken_ **elements;
 } HCountedArray;
 
+typedef struct HBytes_ {
+  const uint8_t *token;
+  size_t len;
+} HBytes;
+
 typedef struct HParsedToken_ {
   HTokenType token_type;
   union {
-    struct {
-      const uint8_t *token;
-      size_t len;
-    } bytes;
+    HBytes bytes;
     int64_t sint;
     uint64_t uint;
     double dbl;