diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2019, Nikita Volkov
+
+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/headed-megaparsec.cabal b/headed-megaparsec.cabal
new file mode 100644
--- /dev/null
+++ b/headed-megaparsec.cabal
@@ -0,0 +1,37 @@
+name: headed-megaparsec
+version: 0.1
+category: Parsers, Parsing, Megaparsec
+synopsis: More informative parser
+homepage: https://github.com/nikita-volkov/headed-megaparsec
+bug-reports: https://github.com/nikita-volkov/headed-megaparsec/issues
+author: Nikita Volkov <nikita.y.volkov@mail.ru>
+maintainer: Nikita Volkov <nikita.y.volkov@mail.ru>
+copyright: (c) 2019, Nikita Volkov
+license: MIT
+license-file: LICENSE
+build-type: Simple
+cabal-version: >=1.10
+
+source-repository head
+  type: git
+  location: git://github.com/nikita-volkov/headed-megaparsec.git
+
+library
+  hs-source-dirs: library
+  default-extensions: ApplicativeDo, Arrows, BangPatterns, ConstraintKinds, DataKinds, DefaultSignatures, DeriveDataTypeable, DeriveFoldable, DeriveFunctor, DeriveGeneric, DeriveTraversable, DuplicateRecordFields, EmptyDataDecls, FlexibleContexts, FlexibleInstances, FunctionalDependencies, GADTs, GeneralizedNewtypeDeriving, LambdaCase, LiberalTypeSynonyms, MagicHash, MultiParamTypeClasses, MultiWayIf, NoImplicitPrelude, NoMonomorphismRestriction, OverloadedStrings, PatternGuards, ParallelListComp, QuasiQuotes, RankNTypes, RecordWildCards, ScopedTypeVariables, StandaloneDeriving, TemplateHaskell, TupleSections, TypeFamilies, TypeOperators, UnboxedTuples
+  default-language: Haskell2010
+  exposed-modules:
+    HeadedMegaparsec
+  other-modules:
+    HeadedMegaparsec.Megaparsec
+    HeadedMegaparsec.Prelude
+  build-depends:
+    base >=4.9 && <5,
+    bytestring >=0.10 && <0.11,
+    case-insensitive >=1.2 && <2,
+    containers >=0.6 && <0.7,
+    megaparsec >=7 && <9,
+    parser-combinators >=1.1 && <1.3,
+    selective >=0.3 && <0.4,
+    text >=1 && <2,
+    unordered-containers >=0.2.10 && <0.3
diff --git a/library/HeadedMegaparsec.hs b/library/HeadedMegaparsec.hs
new file mode 100644
--- /dev/null
+++ b/library/HeadedMegaparsec.hs
@@ -0,0 +1,287 @@
+module HeadedMegaparsec
+(
+  -- * Types
+  HeadedParsec,
+  -- * Execution
+  toParsec,
+  -- * Transformation
+  wrapToHead,
+  label,
+  dbg,
+  filter,
+  -- * Construction
+  parse,
+  endHead,
+)
+where
+
+import HeadedMegaparsec.Prelude hiding (try, head, tail, filter)
+import Control.Applicative.Combinators
+import Text.Megaparsec (Parsec, Stream)
+import qualified HeadedMegaparsec.Megaparsec as Megaparsec
+import qualified Text.Megaparsec as Megaparsec
+import qualified Text.Megaparsec.Debug as Megaparsec
+import qualified Text.Megaparsec.Char as MegaparsecChar
+import qualified Text.Megaparsec.Char.Lexer as MegaparsecLexer
+import qualified Data.Text as Text
+
+{- $setup
+
+>>> :set -XApplicativeDo
+
+-}
+
+-- * Types
+-------------------------
+
+{-|
+Headed parser.
+
+Abstracts over explicit composition between consecutive megaparsec `try` blocks,
+providing for better error messages.
+
+With headed parser you don't need to use `try` at all.
+
+==__Examples__
+
+>>> :{
+  let
+    select :: HeadedParsec Void Text (Maybe [Either Char Int], Maybe Int)
+    select = do
+      head (string' "select")
+      _targets <- optional (head space1 *> targets)
+      _limit <- optional (head space1 *> limit)
+      return (_targets, _limit)
+      where
+        targets = sepBy1 target commaSeparator
+        target =
+          head (Left <$> char '*') <|>
+          head (Right <$> Lexer.decimal)
+        commaSeparator = head (space *> char ',' *> space)
+        limit =
+          head (string' "limit" *> space1) *>
+          tail Lexer.decimal
+    test :: Text -> IO ()
+    test = parseTest (toParsec select <* eof)
+:}
+
+>>> test "select 1, "
+...
+unexpected ','
+...
+
+>>> test "select limit "
+...
+unexpected end of input
+expecting integer or white space
+
+>>> test "select 1, 2 limit 2"
+(Just [Right 1,Right 2],Just 2)
+
+-}
+newtype HeadedParsec err strm a = HeadedParsec (Parsec err strm (Either a (Parsec err strm a)))
+
+{-|
+A helper required for hacking `dbg`.
+-}
+data Showable a = Showable String a
+
+
+-- * Instances
+-------------------------
+
+-- ** Showable
+-------------------------
+
+instance Show (Showable a) where
+  show (Showable msg _) = msg
+
+-- ** HeadedParsec
+-------------------------
+
+instance Functor (HeadedParsec err strm) where
+  fmap fn (HeadedParsec p) = HeadedParsec (fmap (bimap fn (fmap fn)) p)
+
+instance (Ord err, Stream strm) => Applicative (HeadedParsec err strm) where
+  pure = HeadedParsec . pure . Left
+  (<*>) (HeadedParsec p1) (HeadedParsec p2) = HeadedParsec $ do
+    junction1 <- p1
+    case junction1 of
+      Left aToB -> do
+        junction2 <- p2
+        case junction2 of
+          Left a -> return (Left (aToB a))
+          Right tailP2 -> return $ Right $ do
+            a <- tailP2
+            return (aToB a)
+      Right tailP1 -> return $ Right $ do
+        aToB <- tailP1
+        junction2 <- p2
+        case junction2 of
+          Left a -> return (aToB a)
+          Right tailP2 -> do
+            a <- tailP2
+            return (aToB a)
+
+instance (Ord err, Stream strm) => Selective (HeadedParsec err strm) where
+  select (HeadedParsec p1) (HeadedParsec p2) = HeadedParsec $ do
+    junction1 <- p1
+    case junction1 of
+      Left eitherAOrB -> case eitherAOrB of
+        Right b -> return (Left b)
+        Left a -> do
+          junction2 <- p2
+          case junction2 of
+            Left aToB -> return (Left (aToB a))
+            Right tailP2 -> return (Right (fmap ($ a) tailP2))
+      Right tailP1 -> return $ Right $ do
+        eitherAOrB <- tailP1
+        case eitherAOrB of
+          Right b -> return b
+          Left a -> do
+            junction2 <- p2
+            case junction2 of
+              Left aToB -> return (aToB a)
+              Right tailP2 -> fmap ($ a) tailP2
+
+instance (Ord err, Stream strm) => Monad (HeadedParsec err strm) where
+  return = pure
+  (>>=) (HeadedParsec p1) k2 = HeadedParsec $ do
+    junction1 <- p1
+    case junction1 of
+      Left a -> case k2 a of HeadedParsec p2 -> p2
+      Right tailP1 -> return $ Right $ do
+        a <- tailP1
+        Megaparsec.contPossibly $ case k2 a of HeadedParsec p2 -> p2
+
+{-|
+Alternation is performed only the basis of heads.
+Bodies do not participate.
+-}
+instance (Ord err, Stream strm) => Alternative (HeadedParsec err strm) where
+  empty = HeadedParsec empty
+  (<|>) (HeadedParsec p1) (HeadedParsec p2) = HeadedParsec (Megaparsec.try p1 <|> p2)
+
+{-|
+Alternation is performed only the basis of heads.
+Bodies do not participate.
+-}
+instance (Ord err, Stream strm) => MonadPlus (HeadedParsec err strm) where
+  mzero = empty
+  mplus = (<|>)
+
+instance (Ord err, Stream strm) => MonadFail (HeadedParsec err strm) where
+  fail = HeadedParsec . fail
+
+
+-- * Execution
+-------------------------
+
+{-|
+Convert headed parser into megaparsec parser.
+-}
+toParsec :: (Ord err, Stream strm) => HeadedParsec err strm a -> Parsec err strm a
+toParsec (HeadedParsec p) = Megaparsec.contPossibly p
+
+
+-- * Helpers
+-------------------------
+
+mapParsec :: (Parsec err1 strm1 (Either res1 (Parsec err1 strm1 res1)) -> Parsec err2 strm2 (Either res2 (Parsec err2 strm2 res2))) -> HeadedParsec err1 strm1 res1 -> HeadedParsec err2 strm2 res2
+mapParsec fn (HeadedParsec p) = HeadedParsec (fn p)
+
+
+-- * Transformation
+-------------------------
+
+{-|
+Wrap a parser to be usable as a whole in a head block,
+allowing it in effect to be composed with the following parsers into a single `try` when executed,
+no matter whether it contains `endHead` or not.
+-}
+wrapToHead :: (Ord err, Stream strm) => HeadedParsec err strm a -> HeadedParsec err strm a
+wrapToHead = mapParsec $ fmap Left . Megaparsec.contPossibly
+
+{-|
+Label a headed parser.
+Works the same way as megaparsec's `Megaparsec.label`.
+-}
+label :: (Ord err, Stream strm) => String -> HeadedParsec err strm a -> HeadedParsec err strm a
+label label = mapParsec (Megaparsec.label label)
+
+{-|
+Make a parser print debugging information when evaluated.
+The first parameter is a custom label.
+
+This function is a wrapper around `Megaparsec.dbg`.
+It generates two debugging entries: one for head and one for tail.
+-}
+dbg :: (Ord err, Megaparsec.ShowErrorComponent err, Stream strm, Show a) => String -> HeadedParsec err strm a -> HeadedParsec err strm a
+dbg label = mapParsec $ \ p -> do
+  Showable _ junction <- Megaparsec.dbg (label <> "/head") (fmap (either (\ a -> Showable (show a) (Left a)) (Showable "<tail parser>" . Right)) p)
+  case junction of
+    Left a -> return (Left a)
+    Right tailP -> return $ Right $ Megaparsec.dbg (label <> "/tail") tailP
+
+{-|
+Filter the results of parser based on a predicate,
+failing with a parameterized message.
+-}
+filter :: (Ord err, Stream strm) => (a -> String) -> (a -> Bool) -> HeadedParsec err strm a -> HeadedParsec err strm a
+filter err pred = mapParsec $ \ p -> do
+  junction <- p
+  case junction of
+    Left a -> if pred a
+      then return (Left a)
+      else fail (err a)
+    Right tailP -> return $ Right $ do
+      a <- tailP
+      if pred a
+        then return a
+        else fail (err a)
+
+
+-- *
+-------------------------
+
+{-|
+Lift a megaparsec parser as a head parser.
+-}
+head :: (Ord err, Stream strm) => Parsec err strm a -> HeadedParsec err strm a
+head = HeadedParsec . fmap Left
+
+{-|
+Lift a megaparsec parser as a tail parser.
+
+Composing consecutive tails results in one tail.
+
+Composing consecutive head and tail leaves the head still composable with preceding head.
+-}
+tail :: (Stream strm) => Parsec err strm a -> HeadedParsec err strm a
+tail = HeadedParsec . return . Right
+
+{-|
+Lift both head and tail megaparsec parsers, composing their results.
+-}
+headAndTail :: (Ord err, Stream strm) => (head -> tail -> a) -> Parsec err strm head -> Parsec err strm tail -> HeadedParsec err strm a
+headAndTail fn headP tailP = HeadedParsec $ do
+  a <- headP
+  return $ Right $ do
+    b <- tailP
+    return (fn a b)
+
+{-|
+Lift a megaparsec parser.
+-}
+parse :: (Ord err, Stream strm) => Parsec err strm a -> HeadedParsec err strm a
+parse = head
+
+
+-- * Control
+-------------------------
+
+{-|
+Make all the following parsers compose as tail.
+-}
+endHead :: (Stream strm) => HeadedParsec err strm ()
+endHead = HeadedParsec (return (Right (return ())))
diff --git a/library/HeadedMegaparsec/Megaparsec.hs b/library/HeadedMegaparsec/Megaparsec.hs
new file mode 100644
--- /dev/null
+++ b/library/HeadedMegaparsec/Megaparsec.hs
@@ -0,0 +1,19 @@
+{-|
+Extra megaparsec combinators.
+-}
+module HeadedMegaparsec.Megaparsec
+where
+
+import HeadedMegaparsec.Prelude hiding (try, head, body)
+import Text.Megaparsec hiding (some, endBy1, someTill, sepBy1, sepEndBy1)
+import Text.Megaparsec.Char
+import Control.Applicative.Combinators
+import qualified Text.Megaparsec.Char.Lexer as Lexer
+
+
+contPossibly :: (Ord err, Stream strm) => Parsec err strm (Either a (Parsec err strm a)) -> Parsec err strm a
+contPossibly p = do
+  junction <- try p
+  case junction of
+    Left a -> return a
+    Right cont -> cont
diff --git a/library/HeadedMegaparsec/Prelude.hs b/library/HeadedMegaparsec/Prelude.hs
new file mode 100644
--- /dev/null
+++ b/library/HeadedMegaparsec/Prelude.hs
@@ -0,0 +1,103 @@
+module HeadedMegaparsec.Prelude
+( 
+  module Exports,
+  showAsText,
+)
+where
+
+-- base
+-------------------------
+import Control.Applicative as Exports
+import Control.Arrow as Exports hiding (first, second)
+import Control.Category as Exports
+import Control.Concurrent as Exports
+import Control.Exception as Exports
+import Control.Monad as Exports hiding (fail, mapM_, sequence_, forM_, msum, mapM, sequence, forM)
+import Control.Monad.IO.Class as Exports
+import Control.Monad.Fail as Exports
+import Control.Monad.Fix as Exports hiding (fix)
+import Control.Monad.ST as Exports
+import Data.Bifunctor as Exports
+import Data.Bits as Exports
+import Data.Bool as Exports
+import Data.Char as Exports
+import Data.Coerce as Exports
+import Data.Complex as Exports
+import Data.Data as Exports
+import Data.Dynamic as Exports
+import Data.Either as Exports
+import Data.Fixed as Exports
+import Data.Foldable as Exports
+import Data.Function as Exports hiding (id, (.))
+import Data.Functor as Exports
+import Data.Functor.Identity as Exports
+import Data.Int as Exports
+import Data.IORef as Exports
+import Data.Ix as Exports
+import Data.List as Exports hiding (sortOn, isSubsequenceOf, uncons, concat, foldr, foldl1, maximum, minimum, product, sum, all, and, any, concatMap, elem, foldl, foldr1, notElem, or, find, maximumBy, minimumBy, mapAccumL, mapAccumR, foldl')
+import Data.List.NonEmpty as Exports (NonEmpty(..))
+import Data.Maybe as Exports
+import Data.Monoid as Exports hiding (Last(..), First(..), (<>))
+import Data.Ord as Exports
+import Data.Proxy as Exports
+import Data.Ratio as Exports
+import Data.Semigroup as Exports
+import Data.STRef as Exports
+import Data.String as Exports
+import Data.Traversable as Exports
+import Data.Tuple as Exports
+import Data.Unique as Exports
+import Data.Version as Exports
+import Data.Void as Exports
+import Data.Word as Exports
+import Debug.Trace as Exports
+import Foreign.ForeignPtr as Exports
+import Foreign.Ptr as Exports
+import Foreign.StablePtr as Exports
+import Foreign.Storable as Exports hiding (sizeOf, alignment)
+import GHC.Conc as Exports hiding (orElse, withMVar, threadWaitWriteSTM, threadWaitWrite, threadWaitReadSTM, threadWaitRead)
+import GHC.Exts as Exports (lazy, inline, sortWith, groupWith, IsList(fromList, Item))
+import GHC.Generics as Exports (Generic, Generic1)
+import GHC.IO.Exception as Exports
+import Numeric as Exports
+import Prelude as Exports hiding (fail, concat, foldr, mapM_, sequence_, foldl1, maximum, minimum, product, sum, all, and, any, concatMap, elem, foldl, foldr1, notElem, or, mapM, sequence, id, (.))
+import System.Environment as Exports
+import System.Exit as Exports
+import System.IO as Exports
+import System.IO.Error as Exports
+import System.IO.Unsafe as Exports
+import System.Mem as Exports
+import System.Mem.StableName as Exports
+import System.Timeout as Exports
+import Text.ParserCombinators.ReadP as Exports (ReadP, ReadS, readP_to_S, readS_to_P)
+import Text.ParserCombinators.ReadPrec as Exports (ReadPrec, readPrec_to_P, readP_to_Prec, readPrec_to_S, readS_to_Prec)
+import Text.Printf as Exports (printf, hPrintf)
+import Text.Read as Exports (Read(..), readMaybe, readEither)
+import Unsafe.Coerce as Exports
+
+-- selective
+-------------------------
+import Control.Selective as Exports
+
+-- bytestring
+-------------------------
+import Data.ByteString as Exports (ByteString)
+
+-- text
+-------------------------
+import Data.Text as Exports (Text)
+
+-- containers
+-------------------------
+import Data.IntMap.Strict as Exports (IntMap)
+import Data.IntSet as Exports (IntSet)
+import Data.Map.Strict as Exports (Map)
+import Data.Sequence as Exports (Seq)
+import Data.Set as Exports (Set)
+
+-- case-insensitive
+-------------------------
+import Data.CaseInsensitive as Exports (CI, FoldCase)
+
+showAsText :: Show a => a -> Text
+showAsText = show >>> fromString
