diff --git a/bench/Attoparsec.hs b/bench/Attoparsec.hs
--- a/bench/Attoparsec.hs
+++ b/bench/Attoparsec.hs
@@ -7,6 +7,7 @@
 isLatinLetter :: Char -> Bool
 isLatinLetter c = ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')
 
+ws, open, close, ident, sexp :: Parser ()
 ws      = skipMany (satisfy \c -> c == ' ' || c == '\n')
 open    = char '(' >> ws
 close   = char ')' >> ws
@@ -14,10 +15,12 @@
 sexp    = (open *> skipMany1 sexp <* close) <|> ident
 runSexp = parseOnly sexp
 
-longw     = string "thisisalongkeyword"
+longw, longws :: Parser ()
+longw     = () <$ string "thisisalongkeyword"
 longws    = skipMany1 (longw *> ws) <* endOfInput
 runLongws = parseOnly longws
 
+numeral, comma, numcsv :: Parser ()
 numeral   = skipMany1 (satisfy \c -> '0' <= c && c <= '9') >> ws
 comma     = char ',' >> ws
 numcsv    = numeral >> skipMany1 (comma >> numeral) >> endOfInput
diff --git a/bench/Megaparsec.hs b/bench/Megaparsec.hs
--- a/bench/Megaparsec.hs
+++ b/bench/Megaparsec.hs
@@ -17,6 +17,7 @@
 satisfy8 :: (Char -> Bool) -> Parser ()
 satisfy8 f = () <$ satisfy (f . chr . fromIntegral)
 
+ws, open, close, ident, sexp :: Parser ()
 ws      = skipMany (satisfy8 \c -> c == ' ' || c == '\n')
 open    = char8 '(' >> ws
 close   = char8 ')' >> ws
@@ -24,10 +25,12 @@
 sexp    = (open *> skipSome sexp <* close) <|> ident
 runSexp = runParser sexp ""
 
-longw     = chunk "thisisalongkeyword"
+longw, longws :: Parser ()
+longw     = () <$ chunk "thisisalongkeyword"
 longws    = skipSome (longw *> ws) <* eof
 runLongws = runParser longws ""
 
+numeral, comma, numcsv :: Parser ()
 numeral   = skipSome (satisfy8 \c -> '0' <= c && c <= '9') >> ws
 comma     = single (fromIntegral (ord ',')) >> ws
 numcsv    = numeral >> skipSome (comma >> numeral) >> eof
diff --git a/bench/Parsec.hs b/bench/Parsec.hs
--- a/bench/Parsec.hs
+++ b/bench/Parsec.hs
@@ -7,7 +7,7 @@
 isLatinLetter :: Char -> Bool
 isLatinLetter c = ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')
 
-ws      :: Parser ()
+ws, open, close, ident, sexp :: Parser ()
 ws      = skipMany (satisfy \c -> c == ' ' || c == '\n')
 open    = char '(' >> ws
 close   = char ')' >> ws
@@ -15,10 +15,12 @@
 sexp    = (open *> skipMany1 sexp <* close) <|> ident
 runSexp = parse sexp ""
 
-longw     = string "thisisalongkeyword"
+longw, longws :: Parser ()
+longw     = () <$ string "thisisalongkeyword"
 longws    = skipMany1 (longw *> ws) <* eof
 runLongws = parse longws ""
 
+numeral, comma, numcsv :: Parser ()
 numeral   = skipMany1 (satisfy \c -> '0' <= c && c <= '9') >> ws
 comma     = char ',' >> ws
 numcsv    = numeral >> skipMany1 (comma >> numeral) >> eof
diff --git a/flatparse.cabal b/flatparse.cabal
--- a/flatparse.cabal
+++ b/flatparse.cabal
@@ -5,7 +5,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           flatparse
-version:        0.4.1.0
+version:        0.5.0.0
 synopsis:       High-performance parsing from strict bytestrings
 description:    @Flatparse@ is a high-performance parsing library for strict bytestring input. See the README for more information:
                 <https://github.com/AndrasKovacs/flatparse>.
diff --git a/src/FlatParse/Basic.hs b/src/FlatParse/Basic.hs
--- a/src/FlatParse/Basic.hs
+++ b/src/FlatParse/Basic.hs
@@ -174,7 +174,7 @@
 import qualified FlatParse.Basic.Addr as FP.Addr
 
 import qualified Control.Applicative
-import GHC.IO (IO(..))
+import GHC.IO (IO(..), unsafeIOToST)
 import GHC.Exts
 import GHC.ForeignPtr
 import GHC.ST (ST(..))
@@ -235,8 +235,8 @@
 runParserUtf8 pa s = runParser pa (Common.strToUtf8 s)
 
 -- | Run an `ST`-based parser.
-runParserST :: (forall s. ParserST s e a) -> B.ByteString -> Result e a
-runParserST pst buf = unsafeDupablePerformIO (runParserIO pst buf)
+runParserST :: ParserST s e a -> B.ByteString -> ST s (Result e a)
+runParserST pst buf = unsafeIOToST (runParserIO (unsafeCoerce# pst) buf)
 {-# inlinable runParserST #-}
 
 -- | Run an `IO`-based parser.
diff --git a/src/FlatParse/Stateful.hs b/src/FlatParse/Stateful.hs
--- a/src/FlatParse/Stateful.hs
+++ b/src/FlatParse/Stateful.hs
@@ -181,7 +181,7 @@
 import qualified FlatParse.Stateful.Addr as FP.Addr
 
 import qualified Control.Applicative
-import GHC.IO (IO(..))
+import GHC.IO (IO(..), unsafeIOToST)
 import GHC.Exts
 import GHC.ForeignPtr
 import GHC.ST (ST(..))
@@ -243,8 +243,8 @@
 runParserUtf8 pa r !n s = runParser pa r n (Common.strToUtf8 s)
 
 -- | Run an `ST`-based parser. The `Int` argument is the initial state.
-runParserST :: (forall s. ParserST s r e a) -> r -> Int -> B.ByteString -> Result e a
-runParserST pst !r i buf = unsafeDupablePerformIO (runParserIO pst r i buf)
+runParserST :: ParserST s r e a -> r -> Int -> B.ByteString -> ST s (Result e a)
+runParserST pst !r i buf = unsafeIOToST (runParserIO (unsafeCoerce# pst) r i buf)
 {-# inlinable runParserST #-}
 
 -- | Run an `IO`-based parser. The `Int` argument is the initial state.
