diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -27,3 +27,8 @@
 ## 1.0.0.2 -- 2021-08-13
 
 * Added small optimisation to accomodate new core changes: added `try` for all top-level parsers.
+
+## 1.0.0.3 -- 2021-10-29
+
+* Support for `parsley-core-2.0.0` and `parsley-core-1.7.1`.
+* Re-exports less from `parsley-core`, instead using (currently hidden) redefinition.
diff --git a/benchmarks/BrainfuckBench/Main.hs b/benchmarks/BrainfuckBench/Main.hs
--- a/benchmarks/BrainfuckBench/Main.hs
+++ b/benchmarks/BrainfuckBench/Main.hs
@@ -11,7 +11,8 @@
 import Control.DeepSeq        (NFData)
 import GHC.Generics           (Generic)
 import Data.ByteString        (ByteString)
-import Parsley.InputExtras    (Text16(..), CharList(..))
+import Parsley.InputExtras    (CharList(..))
+import Data.Text              (Text)
 --import Parsley.Internal.Verbose ()
 import qualified BrainfuckBench.Parsley.Parser
 import qualified BrainfuckBench.Parsec.Parser
@@ -33,7 +34,7 @@
 brainfuckParsleyS :: String -> Maybe [BrainFuckOp]
 brainfuckParsleyS = $$(Parsley.runParser BrainfuckBench.Parsley.Parser.brainfuck)
 
-brainfuckParsleyT :: Text16 -> Maybe [BrainFuckOp]
+brainfuckParsleyT :: Text -> Maybe [BrainFuckOp]
 brainfuckParsleyT = $$(Parsley.runParser BrainfuckBench.Parsley.Parser.brainfuck)
 
 brainfuckParsleyB :: ByteString -> Maybe [BrainFuckOp]
@@ -50,9 +51,9 @@
   let bfTest :: NFData rep => (FilePath -> IO rep) -> String -> (rep -> Maybe [BrainFuckOp]) -> Benchmark
       bfTest = benchmark ["benchmarks/inputs/helloworld.bf", "benchmarks/inputs/helloworld_golfed.bf", "benchmarks/inputs/compiler.bf"]
   in bgroup "Brainfuck"
-       [ bfTest string          "Parsley (Stream)"          (brainfuckParsleySS . CharList)
+       [ bfTest string          "Parsley (CharList)"        (brainfuckParsleySS . CharList)
        , bfTest string          "Parsley (String)"          brainfuckParsleyS
-       , bfTest text            "Parsley (Text)"            (brainfuckParsleyT . Text16)
+       , bfTest text            "Parsley (Text)"            brainfuckParsleyT
        , bfTest bytestring      "Parsley (ByteString)"      brainfuckParsleyB
        --, bfTest lazy_bytestring "Parsley (Lazy ByteString)" brainfuckParsleyLB
        , bfTest string          "Handrolled"                BrainfuckBench.Handrolled.Parser.brainfuck
diff --git a/benchmarks/BrainfuckBench/Parsley/Parser.hs b/benchmarks/BrainfuckBench/Parsley/Parser.hs
--- a/benchmarks/BrainfuckBench/Parsley/Parser.hs
+++ b/benchmarks/BrainfuckBench/Parsley/Parser.hs
@@ -12,6 +12,9 @@
 --import Parsley.Garnish
 import Language.Haskell.TH.Syntax (Lift(..))
 
+import Parsley.Register
+import Parsley.Defunctionalized
+
 deriving instance Lift BrainFuckOp
 
 brainfuck :: Parser [BrainFuckOp]
@@ -34,3 +37,30 @@
     op '.' = item $> [|Output|]
     op ',' = item $> [|Input|]
     op '[' = between (lexeme item) (try (char ']')) ([|Loop|] <$> bf)
+
+-- This is as closed to the handrolled version as it's possible to get: it's /very/ fast
+-- If register elimination can be performed, this would be equivalent to the handrolled I think
+brainfuck' :: Parser [BrainFuckOp]
+brainfuck' = newRegister_ EMPTY $ \acc ->
+  let walk :: Parser [BrainFuckOp]
+      -- This `eof` is interesting
+      -- The "obvious" way of thinking about this is to just move that `gets_` clause last
+      -- This works because `item` only fails if `eof` wouldn't have done.
+      -- However, at the /moment/, Parsley knows that `eof`'s failure doesn't consume input, and
+      -- optimises the handlers appropriately, but the scope of the failure of the match covers
+      -- the cases too, and so failing there generates a length check etc. Interestingly, the fix
+      -- here is to add a `try` (!!!), which improves performance considerably (but GHC then decides
+      -- not to inline something to make them otherwise identical). That's wild.
+      walk = eof *> gets_ acc [|reverse|]
+         <|> lookAhead (char ']') *> gets_ acc [|reverse|]
+         <|> {- try ( -}match "><+-.,[" item op walk -- )
+         -- <|> gets_ acc [|reverse|]
+      op :: Char -> Parser [BrainFuckOp]
+      op '>' = modify_ acc (APP_H CONS (LIFTED RightPointer)) *> walk
+      op '<' = modify_ acc (APP_H CONS (LIFTED LeftPointer)) *> walk
+      op '+' = modify_ acc (APP_H CONS (LIFTED Increment)) *> walk
+      op '-' = modify_ acc (APP_H CONS (LIFTED Decrement)) *> walk
+      op '.' = modify_ acc (APP_H CONS (LIFTED Output)) *> walk
+      op ',' = modify_ acc (APP_H CONS (LIFTED Input)) *> walk
+      op '[' = modify acc (CONS <$> ([|Loop|] <$> local acc (pure EMPTY) (walk <* char ']'))) *> walk
+  in walk <* eof
diff --git a/parsley.cabal b/parsley.cabal
--- a/parsley.cabal
+++ b/parsley.cabal
@@ -5,7 +5,7 @@
 --                   | +------- breaking API changes
 --                   | | +----- non-breaking API additions
 --                   | | | +--- code changes with no API change
-version:             1.0.0.2
+version:             1.0.0.3
 synopsis:            A fast parser combinator library backed by Typed Template Haskell
 description:         Parsley is a staged selective parser combinator library, which means
                      it does not support monadic operations, and relies on Typed Template
@@ -43,6 +43,9 @@
                        Parsley.InputExtras,
                        Parsley.Precedence
 
+  other-modules:       Parsley.Debug
+                       Parsley.ParserOps
+
   default-extensions:  BangPatterns,
                        DataKinds,
                        GADTs,
@@ -59,7 +62,7 @@
 
 --                     ghc                  >= 8.6     && < 9.2,
   build-depends:       base                 >= 4.10    && < 4.16,
-                       parsley-core         >= 1       && < 2,
+                       parsley-core         >= 1       && < 3,
                        template-haskell     >= 2.14    && < 3,
                        text                 >= 1.2.3   && < 1.3,
   hs-source-dirs:      src/ghc
@@ -136,8 +139,8 @@
   other-extensions:    TemplateHaskellQuotes, TemplateHaskell
   other-modules:       Shared.BenchmarkUtils, Shared.Attoparsec.Extended, Shared.Megaparsec.Extended, Shared.Parsec.Extended
   default-language:    Haskell2010
-  ghc-options:         -rtsopts -fno-spec-constr
-  if false && impl(ghc < 8.8)
+  ghc-options:         -rtsopts
+  if false && impl(ghc < 9)
     build-depends:     dump-core
     ghc-options:       -fplugin=DumpCore
 
diff --git a/src/ghc/Parsley.hs b/src/ghc/Parsley.hs
--- a/src/ghc/Parsley.hs
+++ b/src/ghc/Parsley.hs
@@ -1,5 +1,5 @@
 {-# OPTIONS_GHC -Wno-orphans #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE MultiParamTypeClasses, CPP #-}
 {-|
 Module      : Parsley
 Description : Main functionality exports
@@ -29,17 +29,24 @@
 import Prelude hiding            (readFile)
 import Data.Text.IO              (readFile)
 import Parsley.InputExtras       (Text16(..))
-import Parsley.Internal          (codeGen, Input, eval, compile, Trace(trace))
+import Parsley.Internal          (Input, Trace(trace))
 
 import Parsley.Alternative              as Alternative
 import Parsley.Applicative              as Applicative
 import Parsley.Combinator               as Combinator  (item, char, string, satisfy, notFollowedBy, lookAhead, try)
 import Parsley.Fold                     as Fold        (many, some)
-import Parsley.Internal                 as Core        (Parser, ParserOps)
+import Parsley.Internal                 as Core        (Parser)
+import Parsley.ParserOps                as Core        (ParserOps)
 import Parsley.Internal                 as THUtils     (Quapplicative(..), WQ, Code)
-import Parsley.Internal                 as Primitives  (debug)
+import Parsley.Debug                    as Primitives  (debug)
 import Parsley.Selective                as Selective
 
+#if MIN_VERSION_parsley_core(1,7,1)
+import qualified Parsley.Internal as Internal (parse)
+#else
+import qualified Parsley.Internal as Internal (eval, compile, codeGen)
+#endif
+
 {-|
 The standard way to compile a parser, it returns `Code`, which means
 that it must be /spliced/ into a function definition to produce a
@@ -68,7 +75,11 @@
 runParser :: (Trace, Input input)
           => Parser a                -- ^ The parser to be compiled
           -> Code (input -> Maybe a) -- ^ The generated parsing function
-runParser p = [||\input -> $$(eval [||input||] (compile (try p) codeGen))||]
+#if MIN_VERSION_parsley_core(1,7,1)
+runParser = Internal.parse
+#else
+runParser p = [||\input -> $$(Internal.eval [||input||] (Internal.compile (try p) Internal.codeGen))||]
+#endif
 
 {-|
 This function generates a function that reads input from a file
diff --git a/src/ghc/Parsley/Alternative.hs b/src/ghc/Parsley/Alternative.hs
--- a/src/ghc/Parsley/Alternative.hs
+++ b/src/ghc/Parsley/Alternative.hs
@@ -18,9 +18,32 @@
     (<+>), option, optionally, optional, choice, maybeP, manyTill
   ) where
 
-import Prelude hiding      (pure, (<$>))
-import Parsley.Applicative (pure, (<$>), ($>), (<:>))
-import Parsley.Internal    (makeQ, Parser, Defunc(EMPTY), pattern UNIT, ParserOps, (<|>), empty)
+import Prelude hiding           (pure, (<$>))
+import Parsley.Applicative      (pure, (<$>), ($>), (<:>))
+import Parsley.Defunctionalized (Defunc(EMPTY), pattern UNIT)
+import Parsley.Internal         (makeQ, Parser)
+import Parsley.ParserOps        (ParserOps)
+
+import qualified Parsley.Internal as Internal ((<|>), empty)
+
+{-|
+This combinator always fails.
+
+@since 0.1.0.0
+-}
+empty :: Parser a
+empty = Internal.empty
+
+{-|
+This combinator implements branching within a parser. It is left-biased, so that if the first branch
+succeeds, the second will not be attempted. In accordance with @parsec@ semantics, if the first
+branch failed having consumed input the second branch cannot be taken. (see `Parsley.Combinator.try`)
+
+@since 0.1.0.0
+-}
+infixr 3 <|>
+(<|>) :: Parser a -> Parser a -> Parser a
+(<|>) = (Internal.<|>)
 
 {-|
 This combinator is similar to @(`<|>`)@, except it allows both branches to differ in type by
diff --git a/src/ghc/Parsley/Applicative.hs b/src/ghc/Parsley/Applicative.hs
--- a/src/ghc/Parsley/Applicative.hs
+++ b/src/ghc/Parsley/Applicative.hs
@@ -23,8 +23,41 @@
     (>>)
   ) where
 
-import Prelude hiding   (pure, (<*>), (*>), (<*), (>>), (<$>), fmap, (<$), traverse, sequence, repeat)
-import Parsley.Internal (makeQ, Parser, Defunc(CONS, CONST, ID, EMPTY), pattern FLIP_H, pattern UNIT, ParserOps, pure, (<*>), (*>), (<*))
+import Prelude hiding           (pure, (<*>), (*>), (<*), (>>), (<$>), fmap, (<$), traverse, sequence, repeat)
+import Parsley.Defunctionalized (Defunc(CONS, CONST, ID, EMPTY), pattern FLIP_H, pattern UNIT)
+import Parsley.Internal         (makeQ, Parser)
+import Parsley.ParserOps        (ParserOps, pure)
+
+import qualified Parsley.Internal as Internal ((<*>), (*>), (<*))
+
+-- Applicative Operations
+{-|
+Sequential application of one parser's result to another's. The parsers must both succeed, one after
+the other to combine their results. If either parser fails then the combinator will fail.
+
+@since 0.1.0.0
+-}
+infixl 4 <*>
+(<*>) :: Parser (a -> b) -> Parser a -> Parser b
+(<*>) = (Internal.<*>)
+
+{-|
+Sequence two parsers, keeping the result of the second and discarding the result of the first.
+
+@since 0.1.0.0
+-}
+infixl 4 <*
+(<*) :: Parser a -> Parser b -> Parser a
+(<*) = (Internal.<*)
+
+{-|
+Sequence two parsers, keeping the result of the first and discarding the result of the second.
+
+@since 0.1.0.0
+-}
+infixl 4 *>
+(*>) :: Parser a -> Parser b -> Parser b
+(*>) = (Internal.*>)
 
 -- Functor Operations
 {-|
diff --git a/src/ghc/Parsley/Combinator.hs b/src/ghc/Parsley/Combinator.hs
--- a/src/ghc/Parsley/Combinator.hs
+++ b/src/ghc/Parsley/Combinator.hs
@@ -22,11 +22,51 @@
     lookAhead, notFollowedBy
   ) where
 
-import Prelude hiding      (traverse, (*>))
-import Data.List           (sort)
-import Parsley.Alternative (manyTill)
-import Parsley.Applicative (($>), void, traverse, (<:>), (*>))
-import Parsley.Internal    (Code, Quapplicative(..), Parser, Defunc(LIFTED, EQ_H, CONST, LAM_S), pattern APP_H, pattern COMPOSE_H, satisfy, lookAhead, try, notFollowedBy)
+import Prelude hiding           (traverse, (*>))
+import Data.List                (sort)
+import Parsley.Alternative      (manyTill)
+import Parsley.Applicative      (($>), void, traverse, (<:>), (*>))
+import Parsley.Defunctionalized (Defunc(LIFTED, EQ_H, CONST, LAM_S), pattern APP_H, pattern COMPOSE_H)
+import Parsley.Internal         (Code, Quapplicative(..), Parser)
+import Parsley.ParserOps        (satisfy)
+
+import qualified Parsley.Internal as Internal (try, lookAhead, notFollowedBy)
+
+{-|
+This combinator will attempt to parse a given parser. If it succeeds, the result is returned without
+having consumed any input. If it fails, however, any consumed input remains consumed.
+
+@since 0.1.0.0
+-}
+lookAhead :: Parser a -> Parser a
+lookAhead = Internal.lookAhead
+
+{-|
+This combinator will ensure that a given parser fails. If the parser does fail, a @()@ is returned
+and no input is consumed. If the parser succeeded, then this combinator will fail, however it will
+not consume any input.
+
+@since 0.1.0.0
+-}
+notFollowedBy :: Parser a -> Parser ()
+notFollowedBy = Internal.notFollowedBy
+
+{-|
+This combinator allows a parser to backtrack on failure, which is to say that it will
+not have consumed any input if it were to fail. This is important since @parsec@ semantics demand
+that the second branch of @(`Parsley.Alternative.<|>`)@ can only be taken if the first did not consume input on failure.
+
+Excessive use of `try` will reduce the efficiency of the parser and effect the generated error
+messages. It should only be used in one of two circumstances:
+
+* When two branches of a parser share a common leading prefix (in which case, it is often better
+  to try and factor this out).
+* When a parser needs to be executed atomically (for example, tokens).
+
+@since 0.1.0.0
+-}
+try :: Parser a -> Parser a
+try = Internal.try
 
 {-|
 This combinator will attempt match a given string. If the parser fails midway through, this
diff --git a/src/ghc/Parsley/Debug.hs b/src/ghc/Parsley/Debug.hs
new file mode 100644
--- /dev/null
+++ b/src/ghc/Parsley/Debug.hs
@@ -0,0 +1,18 @@
+module Parsley.Debug (debug) where
+
+import Parsley.Internal (Parser)
+
+import qualified Parsley.Internal as Internal (debug)
+
+{-|
+This combinator can be used to debug parsers that have gone wrong. Simply
+wrap a parser with @debug name@ and when that parser is executed it will
+print a debug trace on entry and exit along with the current context of the
+input.
+
+@since 0.1.0.0
+-}
+debug :: String   -- ^ The name that identifies the wrapped parser in the debug trace
+      -> Parser a -- ^ The parser to track during execution
+      -> Parser a
+debug = Internal.debug
diff --git a/src/ghc/Parsley/Fold.hs b/src/ghc/Parsley/Fold.hs
--- a/src/ghc/Parsley/Fold.hs
+++ b/src/ghc/Parsley/Fold.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE PatternSynonyms #-}
+{-# LANGUAGE PatternSynonyms, CPP #-}
 {-|
 Module      : Parsley.Fold
 Description : The "folding" combinators: chains and iterators
@@ -13,7 +13,7 @@
 -}
 module Parsley.Fold (
     many, some, manyN,
-    skipMany, skipSome, skipManyN,
+    skipMany, skipSome, skipManyN, --loop,
     sepBy, sepBy1, endBy, endBy1, sepEndBy, sepEndBy1,
     chainl1, chainr1, chainl, chainr,
     chainl1', chainr1', chainPre, chainPost,
@@ -21,24 +21,80 @@
     pfoldr1, pfoldl1
   ) where
 
-import Prelude hiding      (pure, (<*>), (<$>), (*>), (<*))
-import Parsley.Alternative ((<|>), option)
-import Parsley.Applicative (pure, (<*>), (<$>), (*>), (<*), (<:>), (<**>), void)
-import Parsley.Internal    (Parser, Defunc(FLIP, ID, COMPOSE, EMPTY, CONS, CONST), ParserOps, pattern FLIP_H, pattern COMPOSE_H, pattern UNIT, chainPre, chainPost)
-import Parsley.Register    (bind, get, modify, newRegister_)
+import Prelude hiding           (pure, (<*>), (<$>), (*>), (<*))
+import Parsley.Alternative      ((<|>), option)
+import Parsley.Applicative      (pure, (<*>), (<$>), (*>), (<*), (<:>), (<**>), void)
+import Parsley.Defunctionalized (Defunc(FLIP, ID, COMPOSE, EMPTY, CONS, CONST), pattern FLIP_H, pattern COMPOSE_H, pattern UNIT)
+import Parsley.Internal         (Parser)
+import Parsley.ParserOps        (ParserOps)
+#if MIN_VERSION_parsley_core(1,7,1)
+import Parsley.Register         (bind, get, put, modify, newRegister, newRegister_)
+#else
+import Parsley.Register         (bind, get, modify, newRegister_)
+#endif
 
-{-chainPre :: Parser (a -> a) -> Parser a -> Parser a
-chainPre op p = newRegister_ ID $ \acc ->
-  let go = modify acc (FLIP_H COMPOSE <$> op) *> go
-       <|> get acc
-  in go <*> p-}
+#if MIN_VERSION_parsley_core(1,7,1)
+import qualified Parsley.Internal as Internal (loop)
+#else
+import qualified Parsley.Internal as Internal (chainPre, chainPost)
+#endif
 
-{-chainPost :: Parser a -> Parser (a -> a) -> Parser a
-chainPost p op = newRegister p $ \acc ->
-  let go = modify acc op *> go
-       <|> get acc
-  in go-}
+#if MIN_VERSION_parsley_core(1,7,1)
+{-|
+The combinator @loop body exit@ parses @body@ zero or more times until it fails. If the final @body@
+failed having not consumed input, @exit@ is performed, otherwise the combinator fails:
 
+> loop body exit = let go = body *> go <|> exit in go
+
+@since 1.1.0.0
+-}
+loop :: Parser () -> Parser a -> Parser a
+loop = Internal.loop
+
+{-|
+This combinator parses repeated applications of an operator to a single final operand. This is
+primarily used to parse prefix operators in expressions.
+
+@since 0.1.0.0
+-}
+chainPre :: Parser (a -> a) -> Parser a -> Parser a
+chainPre op p =
+  newRegister (pure ID) (\r ->
+    loop (put r (pure (FLIP_H COMPOSE) <*> op <*> get r))
+         (get r))
+  <*> p
+
+{-|
+This combinator parses repeated applications of an operator to a single initial operand. This is
+primarily used to parse postfix operators in expressions.
+
+@since 0.1.0.0
+-}
+chainPost :: Parser a -> Parser (a -> a) -> Parser a
+chainPost p op =
+  newRegister p $ \r ->
+    loop (put r (op <*> get r))
+         (get r)
+#else
+{-|
+This combinator parses repeated applications of an operator to a single final operand. This is
+primarily used to parse prefix operators in expressions.
+
+@since 0.1.0.0
+-}
+chainPre :: Parser (a -> a) -> Parser a -> Parser a
+chainPre = Internal.chainPre
+
+{-|
+This combinator parses repeated applications of an operator to a single initial operand. This is
+primarily used to parse postfix operators in expressions.
+
+@since 0.1.0.0
+-}
+chainPost :: Parser a -> Parser (a -> a) -> Parser a
+chainPost = Internal.chainPost
+#endif
+
 -- Parser Folds
 {-|
 @pfoldr f k p@ parses __zero__ or more @p@s and combines the results using the function @f@. When @p@
@@ -92,7 +148,7 @@
 chainl1' f p op = chainPost (f <$> p) (FLIP <$> op <*> p)
 
 {-|
-The classic version of the left-associative chain combinator. See `chainl1'`.
+The classic version of the left-associative chain combinator. See 'chainl1''.
 
 > chainl1 p op = chainl1' ID p op
 
@@ -116,7 +172,7 @@
   in go <**> get acc
 
 {-|
-The classic version of the right-associative chain combinator. See `chainr1'`.
+The classic version of the right-associative chain combinator. See 'chainr1''.
 
 > chainr1 p op = chainr1' ID p op
 
@@ -177,6 +233,7 @@
 skipMany :: Parser a -> Parser ()
 --skipMany p = let skipManyp = p *> skipManyp <|> unit in skipManyp
 skipMany = void . pfoldl CONST UNIT -- the void here will encourage the optimiser to recognise that the register is unused
+--skipMany = flip loop (pure UNIT) . void -- This should be the optimal one, with register removed, but apparently not?! something is amiss, perhaps space leak?
 
 {-|
 Like `manyN`, excepts discards its results.
diff --git a/src/ghc/Parsley/ParserOps.hs b/src/ghc/Parsley/ParserOps.hs
new file mode 100644
--- /dev/null
+++ b/src/ghc/Parsley/ParserOps.hs
@@ -0,0 +1,64 @@
+module Parsley.ParserOps (module Parsley.ParserOps) where
+
+import Prelude hiding (pure)
+import Parsley.Internal (Parser, WQ, Defunc(BLACK))
+
+import qualified Parsley.Internal as Internal (pure, satisfy, conditional)
+
+{-|
+This typeclass is used to allow abstraction of the representation of user-level functions.
+See the instances for information on what these representations are. This may be required
+as a constraint on custom built combinators that make use of one of the minimal required methods
+of this class.
+
+@since 0.1.0.0
+-}
+class ParserOps rep where
+  {-|
+  Lift a value into the parser world without consuming input or having any other effect.
+
+  @since 0.1.0.0
+  -}
+  pure :: rep a -> Parser a
+
+  {-|
+  Attempts to read a single character matching the provided predicate. If it succeeds, the
+  character will be returned and consumed, otherwise the parser will fail having consumed no input.
+
+  @since 0.1.0.0
+  -}
+  satisfy :: rep (Char -> Bool) -- ^ The predicate that a character must satisfy to be parsed
+          -> Parser Char        -- ^ A parser that matches a single character matching the predicate
+
+  {-|
+  @conditional fqs p def@ first parses @p@, then it will try each of the predicates in @fqs@ in turn
+  until one of them returns @True@. The corresponding parser for the first predicate that succeeded
+  is then executes, or if none of the predicates succeeded then the @def@ parser is executed.
+
+  @since 0.1.0.0
+  -}
+  conditional :: [(rep (a -> Bool), Parser b)] -- ^ A list of predicates and their outcomes
+              -> Parser a                      -- ^ A parser whose result is used to choose an outcome
+              -> Parser b                      -- ^ A parser who will be executed if no predicates succeed
+              -> Parser b
+
+{-|
+This is the default representation used for user-level functions and values: plain old code.
+
+@since 0.1.0.0
+-}
+instance ParserOps WQ where
+  pure = pure . BLACK
+  satisfy = satisfy . BLACK
+  conditional = conditional . map (\(f, t) -> (BLACK f, t))
+
+{-|
+This is used to allow defunctionalised versions of many standard Haskell functions to be used
+directly as an argument to relevant combinators.
+
+@since 0.1.0.0
+-}
+instance {-# INCOHERENT #-} x ~ Defunc => ParserOps x where
+  pure = Internal.pure
+  satisfy = Internal.satisfy
+  conditional = Internal.conditional
diff --git a/src/ghc/Parsley/Precedence.hs b/src/ghc/Parsley/Precedence.hs
--- a/src/ghc/Parsley/Precedence.hs
+++ b/src/ghc/Parsley/Precedence.hs
@@ -16,11 +16,12 @@
 -}
 module Parsley.Precedence (module Parsley.Precedence) where
 
-import Prelude hiding      ((<$>))
-import Parsley.Alternative (choice)
-import Parsley.Applicative ((<$>))
-import Parsley.Fold        (chainPre, chainPost, chainl1', chainr1')
-import Parsley.Internal    (WQ, Parser, Defunc(BLACK, ID))
+import Prelude hiding           ((<$>))
+import Parsley.Alternative      (choice)
+import Parsley.Applicative      ((<$>))
+import Parsley.Defunctionalized (Defunc(BLACK, ID))
+import Parsley.Fold             (chainPre, chainPost, chainl1', chainr1')
+import Parsley.Internal         (WQ, Parser)
 
 {-|
 This combinator will construct and expression parser will provided with a table of precedence along
diff --git a/src/ghc/Parsley/Register.hs b/src/ghc/Parsley/Register.hs
--- a/src/ghc/Parsley/Register.hs
+++ b/src/ghc/Parsley/Register.hs
@@ -28,8 +28,44 @@
 import Prelude hiding      (pure, (<*>), (*>), (<*))
 import Parsley.Alternative (empty, (<|>))
 import Parsley.Applicative (pure, (<*>), (*>), (<*))
-import Parsley.Internal    (Parser, ParserOps, Reg, newRegister, get, put)
+import Parsley.Internal    (Parser, Reg)
+import Parsley.ParserOps   (ParserOps)
 import Parsley.Selective   (when, while)
+
+import qualified Parsley.Internal as Internal (newRegister, get, put)
+
+{-|
+Creates a new register initialised with the value obtained from parsing the first
+argument. This register is provided to the second argument, a function that generates a parser
+depending on operations derived from the register. This parser is then performed.
+
+Note: The rank-2 type here serves a similar purpose to that in the @ST@ monad. It prevents the
+register from leaking outside of the scope of the function, safely encapsulating the stateful
+effect of the register.
+
+@since 0.1.0.0
+-}
+newRegister :: Parser a                        -- ^ Parser with which to initialise the register
+            -> (forall r. Reg r a -> Parser b) -- ^ Used to generate the second parser to execute
+            -> Parser b
+newRegister = Internal.newRegister
+
+{-|
+Fetches a value from a register and returns it as its result.
+
+@since 0.1.0.0
+-}
+get :: Reg r a -> Parser a
+get = Internal.get
+
+{-|
+Puts the result of the given parser into the given register. The old value in the register will be
+lost.
+
+@since 0.1.0.0
+-}
+put :: Reg r a -> Parser a -> Parser ()
+put = Internal.put
 
 {-|
 Like `newRegister`, except the initial value of the register is seeded from a pure value as opposed
diff --git a/src/ghc/Parsley/Selective.hs b/src/ghc/Parsley/Selective.hs
--- a/src/ghc/Parsley/Selective.hs
+++ b/src/ghc/Parsley/Selective.hs
@@ -27,7 +27,27 @@
 import Language.Haskell.TH.Syntax (Lift(..))
 import Parsley.Alternative        (empty)
 import Parsley.Applicative        (pure, (<$>), liftA2, unit, constp)
-import Parsley.Internal           (makeQ, Parser, Defunc(ID, EQ_H, IF_S, LAM_S, LET_S, APP_H), ParserOps, conditional, branch)
+import Parsley.Defunctionalized   (Defunc(ID, EQ_H, IF_S, LAM_S, LET_S, APP_H))
+import Parsley.Internal           (makeQ, Parser)
+import Parsley.ParserOps          (ParserOps, conditional)
+
+import qualified Parsley.Internal as Internal (branch)
+
+{-|
+One of the core @Selective@ operations. The behaviour of @branch p l r@ is to first to parse
+@p@, if it fails then the combinator fails. If @p@ succeeded then if its result is a @Left@, then
+the parser @l@ is executed and applied to the result of @p@, otherwise @r@ is executed and applied
+to the right from a @Right@.
+
+Crucially, only one of @l@ or @r@ will be executed on @p@'s success.
+
+@since 0.1.0.0
+-}
+branch :: Parser (Either a b) -- ^ The first parser to execute
+       -> Parser (a -> c)     -- ^ The parser to execute if the first returned a @Left@
+       -> Parser (b -> c)     -- ^ The parser to execute if the first returned a @Right@
+       -> Parser c
+branch = Internal.branch
 
 {-|
 Similar to `branch`, except the given branch is only executed on a @Left@ returned.
