diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+# 1.2.0.0
+
+  * `~`, `!~` builtins require that the regex be the second argument.
+
 # 1.1.0.0
 
   * Add builtin for last field
diff --git a/doc/guide.pdf b/doc/guide.pdf
Binary files a/doc/guide.pdf and b/doc/guide.pdf differ
diff --git a/examples/mtlCtx.jac b/examples/mtlCtx.jac
--- a/examples/mtlCtx.jac
+++ b/examples/mtlCtx.jac
@@ -1,6 +1,8 @@
 {. finds any line matching /MonadState/ or /MonadError/ without
 {. an INLINABLE pragma on the preceding line
 
+{. TODO val fpCtx ≔ line ~* 1 /\{-#.*INLINABLE\s+([a-z][A-Za-z0-9]*)#-\}/
+
 @include'lib/maybe.jac'
 
 fn step(ctx, line) :=
diff --git a/examples/silly.jac b/examples/silly.jac
new file mode 100644
--- /dev/null
+++ b/examples/silly.jac
@@ -0,0 +1,7 @@
+fn count(x):=
+  (+)|0 [:1"x;
+
+let
+  val ext := count {%/\{-#\s*LANGUAGE\s*(.*)#-\}/}{`0}
+  val tot := count $0
+in (ext.tot) end
diff --git a/jacinda.cabal b/jacinda.cabal
--- a/jacinda.cabal
+++ b/jacinda.cabal
@@ -1,6 +1,6 @@
 cabal-version:      2.0
 name:               jacinda
-version:            1.1.0.0
+version:            1.2.0.0
 license:            AGPL-3
 license-file:       COPYING
 maintainer:         vamchale@gmail.com
@@ -73,7 +73,7 @@
         microlens,
         directory,
         filepath,
-        microlens-mtl,
+        microlens-mtl >=0.1.8.0,
         vector,
         recursion >=1.0.0.0,
         split
@@ -105,7 +105,7 @@
     build-depends:
         base,
         jacinda-lib,
-        optparse-applicative,
+        optparse-applicative >=0.13.0.0,
         bytestring
 
     if impl(ghc >=8.0)
diff --git a/man/ja.1 b/man/ja.1
--- a/man/ja.1
+++ b/man/ja.1
@@ -1,4 +1,4 @@
-.\" Automatically generated by Pandoc 2.18
+.\" Automatically generated by Pandoc 2.19.2
 .\"
 .\" Define V font for inline verbatim, using C font in formats
 .\" that render this, and otherwise B font.
@@ -63,6 +63,9 @@
 .PP
 \f[B]#\f[R] Prefix operator: tally (count bytes in string)
 .TP
+\f[B]#*\f[R] Prefix operator: list length
+List a -> a
+.TP
 \f[B],\f[R] Ternary operator: zip with
 (a -> b -> c) -> Stream a -> Stream b -> Stream c
 .TP
@@ -99,10 +102,12 @@
 \f[B]||\f[R] Boolean or
 .PP
 \f[B]!\f[R] Prefix boolean not
-.PP
+.TP
 \f[B]\[ti]\f[R] Matches regex
-.PP
+Str -> Regex -> Bool
+.TP
 \f[B]!\[ti]\f[R] Does not match
+Str -> Regex -> Bool
 .PP
 \f[B]ix\f[R] Line number
 .TP
@@ -202,7 +207,7 @@
 (+)|0 [:1\[dq]$0
 Count lines
 .TP
-[y]|0 {|ix}
+[y]|> {|ix}
 Count lines
 .TP
 (+)|0 [#x+1]\[dq]$0
@@ -216,6 +221,9 @@
 .TP
 (&)|#t (>)\[rs]. {|\[ga]1:f}
 Is the first column strictly increasing?
+.TP
+[y]|> {|\[ga]0\[ti]/\[ha]$/}
+Is the last line blank?
 .SH BUGS
 .PP
 Please report any bugs you may come across to
diff --git a/prelude/fn.jac b/prelude/fn.jac
--- a/prelude/fn.jac
+++ b/prelude/fn.jac
@@ -30,3 +30,12 @@
 
 fn head :=
   ([[:x]|>);
+<<<<<<< Updated upstream
+=======
+
+{. fold two on the same stream
+fn foldTwo(op0, op1, seed0, seed1, stream) :=
+  let
+    val go := \acc. \line. (op0 (acc->1) line . op1 (acc->2) line)
+  in go|(seed0.seed1) stream end;
+>>>>>>> Stashed changes
diff --git a/src/Jacinda/AST.hs b/src/Jacinda/AST.hs
--- a/src/Jacinda/AST.hs
+++ b/src/Jacinda/AST.hs
@@ -55,13 +55,12 @@
 data TB = TyInteger
         | TyFloat
         | TyDate
-        | TyStr
+        | TyStr | TyR
         | TyStream
         | TyVec
         | TyBool
         | TyOption
         | TyUnit
-        -- TODO: tyRegex
         -- TODO: convert float to int
         deriving (Eq, Ord)
 
@@ -95,6 +94,7 @@
     pretty TyVec     = "List"
     pretty TyOption  = "Optional"
     pretty TyUnit    = "𝟙"
+    pretty TyR       = "Regex"
 
 instance Pretty (T a) where
     pretty (TyB _ b)        = pretty b
@@ -251,23 +251,20 @@
          | RegexLit { eLoc :: a, eRr :: BS.ByteString }
          | FloatLit { eLoc :: a, eFloat :: !Double }
          | Lam { eLoc :: a, eBound :: Name a, lamE :: E a }
-         | Dfn { eLoc :: a, eDfn :: E a } -- to be rewritten as a lambda...
-         -- TODO: builtin sum type ? (makes pattern matching easier down the road)
+         | Dfn { eLoc :: a, eDfn :: E a }
          | BBuiltin { eLoc :: a, eBin :: BBin }
          | TBuiltin { eLoc :: a, eTer :: BTer }
          | UBuiltin { eLoc :: a, eUn :: BUn }
          | NBuiltin { eLoc :: a, eNil :: N }
          | Tup { eLoc :: a, esTup :: [E a] }
          | ResVar { eLoc :: a, dfnVar :: DfnVar }
-         | RegexCompiled RurePtr -- holds compiled regex (after normalization)
+         | RegexCompiled RurePtr -- holds compiled regex after normalization
          | Arr { eLoc :: a, elems :: V.Vector (E a) }
          | Anchor { eLoc :: a, eAnchored :: [E a] }
          | Paren { eLoc :: a, eExpr :: E a }
          | OptionVal { eLoc :: a, eMaybe :: Maybe (E a) }
          | Cond { eLoc :: a, eIf :: E a, eThen :: E a, eElse :: E a }
-         -- TODO: regex literal
          deriving (Functor, Generic)
-         -- TODO: side effects: allow since it's strict?
 
 instance Recursive (E a) where
 
@@ -419,7 +416,6 @@
        | IsPrintf
        | HasField Int (T K)
        | Witherable
-       -- TODO: witherable
        deriving (Eq, Ord)
 
 instance Pretty C where
diff --git a/src/Jacinda/Backend/Normalize.hs b/src/Jacinda/Backend/Normalize.hs
--- a/src/Jacinda/Backend/Normalize.hs
+++ b/src/Jacinda/Backend/Normalize.hs
@@ -18,8 +18,7 @@
                                  ) where
 
 import           Control.Exception          (Exception, throw)
-import           Control.Monad.State.Strict (State, evalState, gets, modify, runState)
-import           Data.Bifunctor             (second)
+import           Control.Monad.State.Strict (State, evalState, gets, modify)
 import qualified Data.ByteString            as BS
 import qualified Data.ByteString.Char8      as ASCII
 import           Data.Foldable              (traverse_)
@@ -98,9 +97,6 @@
 mkLetCtx :: Int -> LetCtx
 mkLetCtx i = LetCtx IM.empty (Renames i IM.empty)
 
-hoistEvalM :: Int -> EvalM a -> (a, Int)
-hoistEvalM i = second (max_ . renames_) . flip runState (mkLetCtx i)
-
 runEvalM :: Int
          -> EvalM a
          -> a
@@ -182,14 +178,12 @@
     eI <- eNorm e
     eI' <- eNorm e'
     pure $ case (eI, eI') of
-        (RegexCompiled re, StrLit _ str) -> BoolLit tyBool (isMatch' re str)
         (StrLit _ str, RegexCompiled re) -> BoolLit tyBool (isMatch' re str)
         _                                -> EApp ty (EApp ty' op eI) eI'
 eNorm (EApp ty (EApp ty' op@(BBuiltin _ NotMatches) e) e') = do
     eI <- eNorm e
     eI' <- eNorm e'
     pure $ case (eI, eI') of
-        (RegexCompiled re, StrLit _ str) -> BoolLit tyBool (not $ isMatch' re str)
         (StrLit _ str, RegexCompiled re) -> BoolLit tyBool (not $ isMatch' re str)
         _                                -> EApp ty (EApp ty' op eI) eI'
 eNorm (EApp ty (EApp ty' op@(BBuiltin (TyArr _ (TyB _ TyInteger) _) Max) e) e') = do
@@ -393,7 +387,7 @@
 eNorm e@(Var _ (Name _ (Unique i) _)) = do
     st <- gets binds
     case IM.lookup i st of
-        Just e'@Var{} -> eNorm e' -- no cyclic binds!!
+        Just e'@Var{} -> eNorm e' -- no cyclic binds
         Just e'       -> renameE e' -- FIXME: set outermost type to be type of var...
         Nothing       -> pure e -- default to e in case var was bound in a lambda
 eNorm (EApp ty e@Var{} e') = eNorm =<< (EApp ty <$> eNorm e <*> pure e')
@@ -471,24 +465,11 @@
     case y' of
         Arr _ es -> foldE f' x' es
         _        -> pure $ EApp ty0 (EApp ty1 (EApp ty2 op f') x') y'
--- eNorm (EApp ty0 (EApp ty1 op@(BBuiltin (TyArr _ _ (TyArr _ _ (TyApp _ (TyB _ TyVec) _))) Prior) x) y) = do
-    -- x' <- eNorm x
-    -- y' <- eNorm y
-    -- case y' of
-        -- Arr _ es -> Arr undefined <$> V.priorM (applyOp x') es
-        -- _        -> pure $ EApp ty0 (EApp ty1 op x') y'
--- eNorm (EApp ty0 (EApp ty1 (EApp ty2 op@(TBuiltin (TyArr _ _ (TyApp _ _ (TyApp _ (TyB _ TyVec) _))) ZipW) f) x) y) = do
-    -- f' <- eNorm f
-    -- x' <- eNorm x
-    -- y' <- eNorm y
-    -- case (x', y') of
-        -- (Arr _ es, Arr _ es') -> Arr undefined <$> V.zipWithM (applyOp f') es es'
-        -- _                     -> pure $ EApp ty0 (EApp ty1 (EApp ty2 op f') x') y'
 eNorm (EApp ty0 (EApp ty1 (EApp ty2 op@TBuiltin{} f) x) y) = EApp ty0 <$> (EApp ty1 <$> (EApp ty2 op <$> eNorm f) <*> eNorm x) <*> eNorm y
 -- we include this in case (+) has type (a->a->a) (for instance) if it is
 -- normalizing a decl (which can be ambiguous/general)
 eNorm (EApp ty0 (EApp ty1 op@BBuiltin{} e) e') = EApp ty0 <$> (EApp ty1 op <$> eNorm e) <*> eNorm e'
--- FIXME: specialize types after inlining hm
+-- FIXME: monomorphize types after inlining
 eNorm (EApp ty e@EApp{} e') =
     eNorm =<< (EApp ty <$> eNorm e <*> pure e')
 eNorm (Arr ty es) = Arr ty <$> traverse eNorm es
diff --git a/src/Jacinda/Backend/TreeWalk.hs b/src/Jacinda/Backend/TreeWalk.hs
--- a/src/Jacinda/Backend/TreeWalk.hs
+++ b/src/Jacinda/Backend/TreeWalk.hs
@@ -8,7 +8,6 @@
 
 import           Control.Exception          (Exception, throw)
 import           Control.Monad.State.Strict (State, get, modify, runState)
-import           Control.Recursion          (cata, embed)
 import           Data.Bifunctor             (bimap)
 import qualified Data.ByteString            as BS
 import           Data.Containers.ListUtils  (nubIntOn, nubOrdOn)
@@ -24,7 +23,7 @@
 import           Jacinda.AST
 import           Jacinda.Backend.Normalize
 import           Jacinda.Backend.Printf
-import           Jacinda.Regex
+import           Jacinda.Regex              (captures', find', findCapture, isMatch', splitBy, substr)
 import           Jacinda.Ty.Const
 import           Regex.Rure                 (RurePtr)
 
@@ -37,7 +36,7 @@
 
 instance Exception StreamError where
 
-(!) :: Show a => V.Vector a -> Int -> a
+(!) :: V.Vector a -> Int -> a
 v ! ix = case v V.!? ix of
     Just x  -> x
     Nothing -> throw $ IndexOutOfBounds ix
@@ -76,8 +75,6 @@
 asOpt (OptionVal _ e) = e
 asOpt e               = noRes e "Option"
 
--- TODO: do I want to interleave state w/ eNorm or w/e
-
 -- eval
 eEval :: (Int, BS.ByteString, V.Vector BS.ByteString) -- ^ Field context (for that line)
       -> E (T K)
@@ -124,16 +121,16 @@
         let eI = go e
             eI' = go e'
         in case (eI, eI') of
-            (RegexCompiled reϵ, StrLit _ strϵ) -> BoolLit tyBool (isMatch' reϵ strϵ)
             (StrLit _ strϵ, RegexCompiled reϵ) -> BoolLit tyBool (isMatch' reϵ strϵ)
-            _                                  -> noRes eI "Regex or Str"
+            (StrLit{}, _)                      -> noRes eI' "Regex"
+            _                                  -> noRes eI "Str"
     go (EApp _ (EApp _ (BBuiltin _ NotMatches) e) e') =
         let eI = go e
             eI' = go e'
         in case (eI, eI') of
-            (RegexCompiled reϵ, StrLit _ strϵ) -> BoolLit tyBool (not $ isMatch' reϵ strϵ)
             (StrLit _ strϵ, RegexCompiled reϵ) -> BoolLit tyBool (not $ isMatch' reϵ strϵ)
-            _                                  -> noRes eI "Regex or Str"
+            (StrLit{}, _)                      -> noRes eI' "Regex"
+            _                                  -> noRes eI "Str"
     go (EApp _ (EApp _ (BBuiltin _ Match) e) e') =
         let eI = asRegex (go e)
             eI' = asStr (go e')
@@ -400,7 +397,7 @@
     imap (\ix line -> eEval (mkCtx re ix line) e)
 ir re (Guarded _ pe e) =
     -- TODO: normalize before stream
-    fmap (uncurry (\ix line -> eEval (mkCtx re ix line) e)) . ifilter' (\ix line -> asBool (eEval (mkCtx re ix line) pe))
+    fmap (\(ix, line) -> eEval (mkCtx re ix line) e) . ifilter' (\ix line -> asBool (eEval (mkCtx re ix line) pe))
 ir re (EApp _ (EApp _ (BBuiltin _ Map) op) stream) = fmap (applyUn op) . ir re stream
 ir re (EApp _ (EApp _ (BBuiltin _ Filter) op) stream) =
     filter (asBool . applyUn op) . ir re stream
diff --git a/src/Jacinda/File.hs b/src/Jacinda/File.hs
--- a/src/Jacinda/File.hs
+++ b/src/Jacinda/File.hs
@@ -69,7 +69,6 @@
     a (RegexLitF _ rrϵ) = RegexCompiled (compileDefault rrϵ)
     a (NBuiltinF _ Fp)  = mkStr fp
     a x                 = embed x
-    -- TODO: is cata performant enough?
 
 compileIn :: FileBS -> Program (T K) -> Program (T K)
 compileIn fp (Program ds e) = Program (compileD fp <$> ds) (compileR fp e)
@@ -102,7 +101,7 @@
     (typed, i) <- yeetIO $ runTypeM m (tyProgram ast)
     cont <- yeetIO $ runJac (compileFS (cliFS <|> getFS ast)) i (compileIn (ASCII.pack fp) typed)
     cont $ fmap BSL.toStrict (ASCIIL.lines contents)
-    -- see: BSL.split, BSL.splitWith
+    -- TODO: BSL.split, BSL.splitWith for arbitrary record separators
 
 runOnHandle :: [FilePath]
             -> BSL.ByteString -- ^ Program
diff --git a/src/Jacinda/Parser.y b/src/Jacinda/Parser.y
--- a/src/Jacinda/Parser.y
+++ b/src/Jacinda/Parser.y
@@ -309,12 +309,10 @@
 
 data ParseError a = Unexpected (Token a)
                   | LexErr String
-                  | NoImpl (Name a)
 
 instance Pretty a => Pretty (ParseError a) where
     pretty (Unexpected tok)  = pretty (loc tok) <+> "Unexpected" <+> pretty tok
     pretty (LexErr str)      = pretty (T.pack str)
-    pretty (NoImpl n)        = pretty (Name.loc n) <+> "Signature for" <+> pretty n <+> "is not accompanied by an implementation"
 
 instance Pretty a => Show (ParseError a) where
     show = show . pretty
@@ -327,7 +325,7 @@
 parse = fmap snd . runParse parseF
 
 parseWithMax :: BSL.ByteString -> Either (ParseError AlexPosn) (Int, File)
-parseWithMax = fmap (first fst3) . parseWithInitCtx
+parseWithMax = fmap (first fst3) . runParse parseF
     where fst3 (x, _, _) = x
 
 parseWithInitCtx :: BSL.ByteString -> Either (ParseError AlexPosn) (AlexUserState, File)
diff --git a/src/Jacinda/Rename.hs b/src/Jacinda/Rename.hs
--- a/src/Jacinda/Rename.hs
+++ b/src/Jacinda/Rename.hs
@@ -91,8 +91,6 @@
 mkLam :: [Name a] -> E a -> E a
 mkLam ns e = foldr (\n -> Lam (loc n) n) e ns
 
--- TODO: investigate performance w/out cata
-
 -- | A dfn could be unary or binary - here we guess if it is binary
 hasY :: E a -> Bool
 hasY = cata a where
diff --git a/src/Jacinda/Ty.hs b/src/Jacinda/Ty.hs
--- a/src/Jacinda/Ty.hs
+++ b/src/Jacinda/Ty.hs
@@ -79,6 +79,9 @@
 addVarEnv :: Int -> T K -> TyState a -> TyState a
 addVarEnv i ty (TyState u k cvs v cs) = TyState u k cvs (IM.insert i ty v) cs
 
+addKindEnv :: Int -> K -> TyState a -> TyState a
+addKindEnv i k (TyState u ks cvs v cs) = TyState u (IM.insert i k ks) cvs v cs
+
 addConstraint :: Ord a => (a, T K, T K) -> TyState a -> TyState a
 addConstraint c (TyState u k cvs v cs) = TyState u k cvs v (S.insert c cs)
 
@@ -130,7 +133,7 @@
     | length tys == length tys' = unifyPrep um (zip3 (repeat l) tys tys' ++ tyss)
     | otherwise = throwError (UnificationFailed l (void ty) (void ty'))
 unifyMatch um ((_, TyVar _ n@(Name _ (Unique k) _), ty@(TyVar _ n')):tys)
-    | n == n' = unifyPrep um tys -- a type variable is always equal to itself, don't bother inserting this!
+    | n == n' = unifyPrep um tys
     | otherwise = IM.insert k ty <$> unifyPrep (IM.insert k ty um) tys
 unifyMatch _ ((l, ty, ty'):_) = throwError (UnificationFailed l (void ty) (void ty'))
 
@@ -166,14 +169,16 @@
     Name n (Unique $ st+1) k
         <$ modify (mapMaxU (+1))
 
+namek :: Name K -> TypeM a (Name K)
+namek n =
+    modify (addKindEnv (unUnique$unique n) (loc n)) $> n
+
 higherOrder :: T.Text -> TypeM a (Name K)
-higherOrder t = freshName t (KArr Star Star)
--- TODO: this should modify kind environment
+higherOrder t = freshName t (KArr Star Star) >>= namek
 
 -- of kind 'Star'
 dummyName :: T.Text -> TypeM a (Name K)
-dummyName n = freshName n Star
--- TODO: this should modify kind environment
+dummyName n = freshName n Star >>= namek
 
 addC :: Ord a => Name b -> (C, a) -> IM.IntMap (S.Set (C, a)) -> IM.IntMap (S.Set (C, a))
 addC (Name _ (Unique i) _) c = IM.alter (Just . go) i where
@@ -255,9 +260,9 @@
                       | otherwise        -> throwError $ Expected (tLoc ty1) k0
         k0                               -> throwError $ Expected (KArr Star Star) k0
 
--- TODO: this will need some class context if we permit custom types (Optional)
 checkType :: Ord a => T K -> (C, a) -> TypeM a ()
 checkType TyVar{} _                            = pure () -- TODO: I think this is right
+checkType (TyB _ TyR) (IsSemigroup, _)         = pure ()
 checkType (TyB _ TyStr) (IsSemigroup, _)       = pure ()
 checkType (TyB _ TyInteger) (IsSemigroup, _)   = pure ()
 checkType (TyB _ TyInteger) (IsNum, _)         = pure ()
@@ -348,7 +353,7 @@
 checkAmb e@(UBuiltin ty _) | isAmbiguous ty = throwError $ Ambiguous ty (void e)
 checkAmb (Implicit _ e') = checkAmb e'
 checkAmb (Guarded _ p e') = checkAmb p *> checkAmb e'
-checkAmb (EApp _ e' e'') = checkAmb e' *> checkAmb e'' -- more precise errors, don't fail yet! (if they aren't ambiguous, it shouldn't be
+checkAmb (EApp _ e' e'') = checkAmb e' *> checkAmb e'' -- more precise errors, don't fail yet!
 checkAmb (Tup _ es) = traverse_ checkAmb es
 checkAmb e@(Arr ty _) | isAmbiguous ty = throwError $ Ambiguous ty (void e)
 checkAmb e@(Var ty _) | isAmbiguous ty = throwError $ Ambiguous ty (void e)
@@ -420,7 +425,7 @@
 tyE0 (IntLit _ i)            = pure $ IntLit tyI i
 tyE0 (FloatLit _ f)          = pure $ FloatLit tyF f
 tyE0 (StrLit _ str)          = pure $ StrLit tyStr str
-tyE0 (RegexLit _ rr)         = pure $ RegexLit tyStr rr
+tyE0 (RegexLit _ rr)         = pure $ RegexLit tyR rr
 tyE0 (Column _ i)            = pure $ Column (tyStream tyStr) i
 tyE0 (IParseCol _ i)         = pure $ IParseCol (tyStream tyI) i
 tyE0 (FParseCol _ i)         = pure $ FParseCol (tyStream tyF) i
@@ -442,16 +447,16 @@
 tyE0 (BBuiltin l Neq)        = BBuiltin <$> tyEq l <*> pure Neq
 tyE0 (BBuiltin l Min)        = BBuiltin <$> tyM l <*> pure Min
 tyE0 (BBuiltin l Max)        = BBuiltin <$> tyM l <*> pure Max
-tyE0 (BBuiltin _ Split)      = pure $ BBuiltin (tyArr tyStr (tyArr tyStr (mkVec tyStr))) Split
+tyE0 (BBuiltin _ Split)      = pure $ BBuiltin (tyArr tyStr (tyArr tyR (mkVec tyStr))) Split
 tyE0 (BBuiltin _ Splitc)     = pure $ BBuiltin (tyArr tyStr (tyArr tyStr (mkVec tyStr))) Splitc
-tyE0 (BBuiltin _ Matches)    = pure $ BBuiltin (tyArr tyStr (tyArr tyStr tyBool)) Matches
-tyE0 (BBuiltin _ NotMatches) = pure $ BBuiltin (tyArr tyStr (tyArr tyStr tyBool)) NotMatches
+tyE0 (BBuiltin _ Matches)    = pure $ BBuiltin (tyArr tyStr (tyArr tyR tyBool)) Matches
+tyE0 (BBuiltin _ NotMatches) = pure $ BBuiltin (tyArr tyStr (tyArr tyR tyBool)) NotMatches
 tyE0 (UBuiltin _ Tally)      = pure $ UBuiltin (tyArr tyStr tyI) Tally
 tyE0 (BBuiltin _ Div)        = pure $ BBuiltin (tyArr tyF (tyArr tyF tyF)) Div
 tyE0 (UBuiltin _ Not)        = pure $ UBuiltin (tyArr tyBool tyBool) Not
 tyE0 (BBuiltin _ And)        = pure $ BBuiltin (tyArr tyBool (tyArr tyBool tyBool)) And
 tyE0 (BBuiltin _ Or)         = pure $ BBuiltin (tyArr tyBool (tyArr tyBool tyBool)) Or
-tyE0 (BBuiltin _ Match)      = pure $ BBuiltin (tyArr tyStr (tyArr tyStr (tyOpt $ TyTup Star [tyI, tyI]))) Match
+tyE0 (BBuiltin _ Match)      = pure $ BBuiltin (tyArr tyStr (tyArr tyR (tyOpt $ TyTup Star [tyI, tyI]))) Match
 tyE0 (TBuiltin _ Substr)     = pure $ TBuiltin (tyArr tyStr (tyArr tyI (tyArr tyI tyStr))) Substr
 tyE0 (UBuiltin _ IParse)     = pure $ UBuiltin (tyArr tyStr tyI) IParse
 tyE0 (UBuiltin _ FParse)     = pure $ UBuiltin (tyArr tyStr tyF) FParse
@@ -549,7 +554,6 @@
         fTy = tyArr (tyArr a' b') (tyArr (hkt f' a') (hkt f' b'))
     modify (mapClassVars (addC f (Functor, l)))
     pure $ BBuiltin fTy Map
--- (b -> a -> b) -> b -> Stream a -> b
 tyE0 (TBuiltin l Fold) = do
     b <- dummyName "b"
     a <- dummyName "a"
@@ -569,7 +573,7 @@
     modify (mapClassVars (addC f (Foldable, l)))
     pure $ BBuiltin fTy Fold1
 tyE0 (TBuiltin _ Captures) =
-    pure $ TBuiltin (tyArr tyStr (tyArr tyI (tyArr tyStr (tyOpt tyStr)))) Captures
+    pure $ TBuiltin (tyArr tyStr (tyArr tyI (tyArr tyR (tyOpt tyStr)))) Captures
 -- (a -> a -> a) -> Stream a -> Stream a
 tyE0 (BBuiltin _ Prior) = do
     a <- dummyName "a"
@@ -604,11 +608,10 @@
         fTy = tyArr b' (tyArr (tyArr a' b') (tyArr (tyOpt a') b'))
     pure $ TBuiltin fTy Option
 tyE0 (TBuiltin _ AllCaptures) =
-    pure $ TBuiltin (tyArr tyStr (tyArr tyI (tyArr tyStr (mkVec tyStr)))) AllCaptures
+    pure $ TBuiltin (tyArr tyStr (tyArr tyI (tyArr tyR (mkVec tyStr)))) AllCaptures
 tyE0 (Implicit _ e) = do
     e' <- tyE0 e
     pure $ Implicit (tyStream (eLoc e')) e'
--- (a -> b -> c) -> Stream a -> Stream b -> Stream c
 tyE0 (Guarded l e streamE) = do
     streamE' <- tyE0 streamE
     e' <- tyE0 e
diff --git a/src/Jacinda/Ty/Const.hs b/src/Jacinda/Ty/Const.hs
--- a/src/Jacinda/Ty/Const.hs
+++ b/src/Jacinda/Ty/Const.hs
@@ -1,5 +1,5 @@
 module Jacinda.Ty.Const ( tyStream
-                        , tyStr
+                        , tyStr, tyR
                         , tyI
                         , tyF
                         , tyBool
@@ -25,6 +25,9 @@
 
 tyStr :: T K
 tyStr = TyB Star TyStr
+
+tyR :: T K
+tyR = TyB Star TyR
 
 hkt :: T K -> T K -> T K
 hkt = TyApp Star
