diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2018 Peter Simons
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/parsec-class.cabal b/parsec-class.cabal
new file mode 100644
--- /dev/null
+++ b/parsec-class.cabal
@@ -0,0 +1,29 @@
+name:          parsec-class
+version:       1.0.0.0
+synopsis:      Class of types that can be constructed from their text representation
+description:   This library provides the type class 'HasParser' as a dual to 'Pretty'.
+               Instances of this class provide a parser than can be used to construct the
+               type from its text representation.
+license:       MIT
+license-file:  LICENSE
+author:        Peter Simons
+maintainer:    simons@cryp.to
+tested-with:   GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.3
+category:      Text
+homepage:      https://github.com/peti/parsec-class
+bug-reports:   https://github.com/peti/parsec-class/issues
+build-type:    Simple
+cabal-version: >= 1.10
+
+source-repository head
+  type:     git
+  location: git://github.com/peti/parsec-class.git
+
+library
+  exposed-modules:  Text.Parsec.Class
+                    Text.Parsec.Class.Orphans
+  hs-source-dirs:   src
+  build-depends:    base >= 4.9 && < 5, parsec >= 3
+  default-language: Haskell2010
+  other-extensions: RankNTypes
+                    FlexibleContexts
diff --git a/src/Text/Parsec/Class.hs b/src/Text/Parsec/Class.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Parsec/Class.hs
@@ -0,0 +1,91 @@
+{-# LANGUAGE FlexibleContexts, RankNTypes #-}   -- for 'CharParser'
+
+-- | 'HasParser' can be considered a dual to 'Pretty' like 'Read' is to 'Show'.
+-- The class provides "Data.Parsec" parsers for its instances that construct
+-- the type from its textual representation. Combined with the 'parseM' and
+-- 'parse' convenience functions, this class makes parsing simple. Unlike
+-- 'Read', Parsec parsers return reasonable error messages in case of failure.
+-- Also, there is a rich set of combinators and additional libraries available
+-- for re-use.
+
+module Text.Parsec.Class
+  ( CharParser, HasParser(parser), ErrorContext
+  , parseM, parse
+  , -- * Re-exports from Text.Parsec
+    module Text.Parsec
+  )
+  where
+
+import Prelude hiding ( fail )
+
+import Text.Parsec.Class.Orphans ( )   -- TODO: This is unnecessary.
+
+import Control.Exception ( throw )
+import Control.Monad.Fail
+import Data.Functor.Identity
+import Numeric.Natural ( Natural )
+import Text.Parsec hiding ( parse )
+
+-- | A simplified 'ParsecT' parser that consumes some kind of character stream
+-- without requiring any particular state state.
+
+type CharParser st input m a = Stream st m Char => ParsecT st input m a
+
+-- | Types that are instances of this class can be parsed and constructed from
+-- some character based text representation.
+
+class HasParser a where
+  parser :: CharParser st input m a
+
+-- | Parsers functions like 'parse' or 'parseM' use this type to provide a
+-- helpful context in case the parser failes. Parsec uses the synonym
+-- 'SourceName' for the same purpose, but in fact this type doesn't necessarily
+-- have to be a file name. It can be any name or identifier. Oftentimes, it
+-- it's useful to pass the name of the type that the parser attempted to parse.
+
+type ErrorContext = String
+
+-- | Convenience wrapper around 'runParserT' that uses the 'HasParser' class to
+-- determine the desired parser for the given result type. The function reports
+-- syntax errors via 'fail'.
+--
+-- >>> parseM "Natural" "987654321" :: IO Natural
+-- 987654321
+-- >>> parseM "Natural" "123456789" :: Maybe Natural
+-- Just 123456789
+--
+-- Please note that parsers run this way do not ignore any white space:
+--
+-- >>> parseM "Natural" " 1" :: Maybe Natural
+-- Nothing
+-- >>> parseM "Natural" "1 " :: Maybe Natural
+-- Nothing
+
+parseM :: (MonadFail m, Stream input m Char, HasParser a) => ErrorContext -> input -> m a
+parseM ctx x = runParserT (parser <* eof) () ctx x >>= either (fail . show) return
+
+-- | Convenience wrapper around 'runParser' that uses the 'HasParser' class to
+-- determine the desired parser for the given result type. The function reports
+-- syntax errors by 'throw'ing 'ParseError'. This approach is inherently impure
+-- and complicates error handling greatly. Use this function only on occasions
+-- where parser errors are fatal errors that your code cannot recover from. In
+-- almost all cases, 'parseM' is the better choice.
+--
+-- >>> parse "Natural" "12345" :: Natural
+-- 12345
+--
+-- Like 'parseM', this function does not skip over any white space. Use
+-- Parsec's primitive 'runParser' or 'runParserT' functions if you don't like
+-- this behavior:
+--
+-- >>> runParser (spaces >> parser) () "Natural" "  1  " :: Either ParseError Natural
+-- Right 1
+
+parse :: (Stream input Identity Char, HasParser a) => ErrorContext -> input -> a
+parse ctx = either throw id . runParser (parser <* eof) () ctx
+
+
+----- Useful HasParser instances ----------------------------------------------
+
+instance HasParser Natural where
+  parser = read <$> many1 digit
diff --git a/src/Text/Parsec/Class/Orphans.hs b/src/Text/Parsec/Class/Orphans.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Parsec/Class/Orphans.hs
@@ -0,0 +1,8 @@
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+module Text.Parsec.Class.Orphans where
+
+import Control.Exception
+import Text.Parsec.Error
+
+instance Exception ParseError
