diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+# 0.4.0
+* Drop the quasi-quoters
+* Drop the "Lens" module in preference to a dependency on the "basic-lens" library
+* Generate strict record types
+* Export the types from the root module
+
 # 0.3.1
 * Support for arrow types
 * Higher arity bugs fix
diff --git a/Setup.hs b/Setup.hs
--- a/Setup.hs
+++ b/Setup.hs
@@ -1,6 +1,2 @@
-module Main where
-
-import Distribution.Extra.Doctest ( defaultMainWithDoctests )
-
-main :: IO ()
-main = defaultMainWithDoctests "doctest"
+import Distribution.Simple
+main = defaultMain
diff --git a/demo/Main.hs b/demo/Main.hs
deleted file mode 100644
--- a/demo/Main.hs
+++ /dev/null
@@ -1,49 +0,0 @@
-{-# LANGUAGE NoImplicitPrelude, QuasiQuotes, DataKinds #-}
-module Main where
-
-import BasePrelude
-import Record
-import Record.Lens
-
-
-main =
-  return ()
-
-
-type Person = 
-  [record| {name :: String, birthday :: {year :: Int, month :: Int, day :: Int}} |]
-
-type Event =
-  [record| {name :: String, date :: {year :: Int, month :: Int, day :: Int}} |]
-
-person =
-  [record| {name = "Simon Peyton Jones", 
-            birthday = {year = 1958, month = 1, day = 18}} |]
-
-getPersonBirthdayYear :: Person -> Int
-getPersonBirthdayYear =
-  view [lens|birthday.year|]
-
-setPersonBirthdayYear :: Int -> Person -> Person
-setPersonBirthdayYear =
-  set [lens|birthday.year|]
-
-personBirthdayYearLens :: Lens Person Person Int Int
-personBirthdayYearLens =
-  [lens|birthday.year|]
-
-personBirthdayYearLens' :: Lens Person Person Int Int
-personBirthdayYearLens' =
-  [lens|birthday|] . [lens|year|]
-
-tupleLens :: Lens (Int, Char, String) (Int, Char, a) String a
-tupleLens =
-  [lens|3|]
-
-mapThirdElement :: (Char -> b) -> (Int, String, Char) -> (Int, String, b)
-mapThirdElement =
-  over [lens|3|]
-
-functionOnARecord :: [record| {name :: String, age :: [Int]}|] -> [Int]
-functionOnARecord =
-  view [lens|age|]
diff --git a/doctest/Main.hs b/doctest/Main.hs
deleted file mode 100644
--- a/doctest/Main.hs
+++ /dev/null
@@ -1,13 +0,0 @@
-module Main where
-
-import Prelude
-import Build_doctests (flags, pkgs, module_sources)
-import Data.Foldable (traverse_)
-import Test.DocTest
-
-main :: IO ()
-main = do
-  traverse_ putStrLn args
-  doctest args
-  where
-    args = flags ++ pkgs ++ module_sources
diff --git a/library/Record.hs b/library/Record.hs
--- a/library/Record.hs
+++ b/library/Record.hs
@@ -1,257 +1,74 @@
-module Record
-(
-  record,
-  lens,
-  -- ** Shorthands
-  r,
-  l,
-)
-where
+-- |
+-- Types and instances of anonymous records.
+module Record where
 
-import BasePrelude
-import Language.Haskell.TH
-import Language.Haskell.TH.Syntax
-import Language.Haskell.TH.Quote
-import qualified Record.Types as Types
-import qualified Record.Lens as Lens
-import qualified Record.Parser as Parser
-import qualified Data.Text as T
+import BasePrelude hiding (Proxy)
+import Data.Functor.Identity
+import GHC.TypeLits
+import Foreign.Storable
+import Foreign.Ptr (plusPtr)
+import Control.Lens.Basic
+import qualified Record.TH as TH
 
 
--- | A shorthand alias to 'record'.
-r :: QuasiQuoter
-r = record
-
--- | A shorthand alias to 'lens'.
-l :: QuasiQuoter
-l = lens
-
 -- |
--- A quasiquoter, which generates record expressions and types,
--- depending on the context it's used in.
--- 
--- Here is how you can use it to declare types:
--- 
--- >type Person = 
--- >  [record| {name :: String, birthday :: {year :: Int, month :: Int, day :: Int}} |]
--- 
--- To declare functions:
--- 
--- >getAge :: [record| {name :: String, age :: Int} |] -> Int
--- 
--- To declare values:
--- 
--- >person :: Person
--- >person =
--- >  [record| {name = "Grigori Yakovlevich Perelman", 
--- >            birthday = {year = 1966, month = 6, day = 13}} |]
--- 
-record :: QuasiQuoter
-record =
-  QuasiQuoter
-    (exp)
-    (const $ fail "Pattern context is not supported")
-    (type')
-    (const $ fail "Declaration context is not supported")
-  where
-    exp =
-      join . fmap (either fail return . renderExp) .
-      either (fail . showString "Parser failure: ") return .
-      Parser.run (Parser.qq Parser.exp) . fromString
-    type' =
-      join . fmap (either fail return . renderType) .
-      either (fail . showString "Parser failure: ") return .
-      Parser.run (Parser.qq Parser.type') . fromString
+-- A specialised version of "Data.Proxy.Proxy".
+-- Defined for compatibility with \"base-4.6\",
+-- since @Proxy@ was only defined in \"base-4.7\".
+data FieldName (t :: Symbol)
 
 -- |
--- A quasiquoter, which generates a 'Lens.Lens'.
--- Lens is your interface to accessing and modifying the fields of a record.
--- 
--- Here is how you can use it:
--- 
--- >getPersonBirthdayYear :: Person -> Int
--- >getPersonBirthdayYear =
--- >  Record.Lens.view ([lens|birthday|] . [lens|year|])
--- 
--- For your convenience you can compose lenses from inside of the quotation:
--- 
--- >setPersonBirthdayYear :: Int -> Person -> Person
--- >setPersonBirthdayYear =
--- >  Record.Lens.set [lens|birthday.year|]
--- 
--- You can also use this function to manipulate tuples of arity up to 24:
+-- Defines a lens to manipulate some value of a type by a type-level name,
+-- using the string type literal functionality.
+--
+-- Instances are provided for all records and for tuples of arity of up to 24.
+--
+-- Here's how you can use it with tuples:
+--
+-- >trd :: Field "3" a a' v v' => a -> v
+-- >trd = view (fieldLens (undefined :: FieldName "3"))
 -- 
--- >mapThirdElement :: (Char -> Char) -> (Int, String, Char) -> (Int, String, Char)
--- >mapThirdElement =
--- >  Record.Lens.over [lens|3|]
-lens :: QuasiQuoter
-lens =
-  QuasiQuoter
-    (exp)
-    (const $ fail "Pattern context is not supported")
-    (const $ fail "Type context is not supported")
-    (const $ fail "Declaration context is not supported")
-  where
-    exp =
-      either (fail . showString "Parser failure: ") return .
-      fmap renderLens .
-      Parser.run (Parser.qq Parser.lens) . fromString
+-- The function above will get you the third item of any tuple, which has it.
+class Field (n :: Symbol) a a' v v' | n a -> v, n a' -> v', n a v' -> a', n a' v -> a where
+  fieldLens :: FieldName n -> Lens a a' v v'
 
-renderLens :: Parser.Lens -> Exp
-renderLens =
-  foldl1 composition .
-  fmap renderSingleLens
-  where
-    composition a b = 
-      UInfixE a (VarE '(.)) b
+instance Field "1" (Identity v1) (Identity v1') v1 v1' where
+  fieldLens = const $ \f -> fmap Identity . f . runIdentity
 
-renderSingleLens :: T.Text -> Exp
-renderSingleLens =
-  AppE (VarE 'Types.fieldLens) .
-  SigE (VarE 'undefined) .
-  AppT (ConT ''Types.FieldName) .
-  LitT . StrTyLit . T.unpack
+-- Generate the tuple instances of the Field class:
+return $ do
+  arity <- [2 .. 24]
+  fieldIndex <- [1 .. arity]
+  return $ TH.tupleFieldInstanceDec arity fieldIndex
 
-renderRecordType :: Parser.RecordType -> Either String Type
-renderRecordType l =
-  checkDuplicateLabels >> getRecordTypeName >>= constructType
-  where
-    checkDuplicateLabels =
-      maybe (return ()) (Left . showString "Duplicate labels: " . show) $
-      mfilter (not . null) . Just $ 
-      map (fst . head) $
-      filter ((> 1) . length) $
-      groupWith fst l
-    getRecordTypeName =
-      maybe (Left (showString "Record arity " . shows arity . shows " is not supported" $ ""))
-            (Right) $
-      recordTypeNameByArity arity
-      where
-        arity = length l
-    constructType n =
-      foldl (\a (l, t) -> AppT <$> (AppT <$> a <*> pure (textLitT l)) <*> (renderType t))
-            (pure (ConT n))
-            (sortWith fst l)
-      where
-        textLitT =
-          LitT . StrTyLit . T.unpack
+-- |
+-- A simplified field constraint,
+-- which excludes the possibility of type-changing updates.
+type Field' n a v =
+  Field n a a v v
 
-recordTypeNameByArity :: Int -> Maybe Name
-recordTypeNameByArity arity =
-  if arity > 24 || arity < 1
-    then Nothing
-    else Just (Name (OccName ("Record" <> show arity)) ns)
-  where
-    ns = case ''Types.Record1 of Name _ x -> x
 
-recordConNameByArity :: Int -> Maybe Name
-recordConNameByArity arity =
-  if arity > 24 || arity < 1
-    then Nothing
-    else Just (Name (OccName ("Record" <> show arity)) ns)
-  where
-    ns = case 'Types.Record1 of Name _ x -> x
+-- * Record types and instances
+-------------------------
 
-renderType :: Parser.Type -> Either String Type
-renderType =
-  \case
-    Parser.Type_App a b  -> AppT <$> renderType a <*> renderType b
-    Parser.Type_Var n    -> return $ VarT (mkName (T.unpack n))
-    Parser.Type_Con n    -> return $ ConT (mkName (T.unpack n))
-    Parser.Type_Tuple a  -> return $ TupleT a
-    Parser.Type_Arrow    -> return $ ArrowT
-    Parser.Type_List     -> return $ ListT
-    Parser.Type_Record a -> renderRecordType a
+-- Generate the record types and instances:
+return $ do
+  arity <- [1 .. 24]
+  strict <- [False, True]
+  let
+    recordType =
+      TH.recordTypeDec strict arity
+    fieldInstances =
+      do
+        fieldIndex <- [1 .. arity]
+        return $ TH.recordFieldInstanceDec strict arity fieldIndex
+    storableInstance =
+      TH.recordStorableInstanceDec strict arity
+    in recordType : storableInstance : fieldInstances
 
-renderExp :: Parser.Exp -> Either String Exp
-renderExp =
-  \case
-    Parser.Exp_Record r   -> renderRecordExp r
-    Parser.Exp_Var n      -> return $ VarE (mkName (T.unpack n))
-    Parser.Exp_Con n      -> return $ ConE (mkName (T.unpack n))
-    Parser.Exp_TupleCon a -> return $ ConE (tupleDataName a)
-    Parser.Exp_Nil        -> return $ ConE ('[])
-    Parser.Exp_Lit l      -> return $ LitE (renderLit l)
-    Parser.Exp_App a b    -> AppE <$> renderExp a <*> renderExp b
-    Parser.Exp_List l     -> ListE <$> traverse renderExp l
-    Parser.Exp_Sig e t    -> SigE <$> renderExp e <*> renderType t
 
-renderRecordExp :: Parser.RecordExp -> Either String Exp
-renderRecordExp l =
-  checkDuplicateLabels >> getConLambda >>= constructExp
-  where
-    checkDuplicateLabels =
-      maybe (return ()) (Left . showString "Duplicate labels: " . show) $
-      mfilter (not . null) . Just $ 
-      map (fst . head) $
-      filter ((> 1) . length) $
-      groupWith fst l
-    getConLambda =
-      maybe (Left (showString "Record arity " . shows arity . shows " is not supported" $ ""))
-            (Right) $
-      conLambdaExp arity
-      where
-        arity = length l
-    constructExp lam =
-      foldl (\a (n, e) -> AppE <$> (AppE <$> a <*> pure (proxy n)) <*> renderExp e)
-            (pure lam)
-            (sortWith fst l)
-      where
-        proxy n =
-          SigE (VarE 'undefined) 
-               (AppT (ConT ''Types.FieldName) (LitT (StrTyLit (T.unpack n))))
-
-renderLit :: Parser.Lit -> Lit
-renderLit =
-  \case
-    Parser.Lit_Char c -> CharL c
-    Parser.Lit_String t -> StringL (T.unpack t)
-    Parser.Lit_Integer i -> IntegerL i
-    Parser.Lit_Rational r -> RationalL r
-
--- |
--- Allows to specify names in types signatures,
--- leaving the value type resolution to the compiler.
--- 
--- E.g.,
--- 
--- >(\_ v1 _ v2 -> Record2 v1 v2) :: Types.FieldName n1 -> v1 -> Types.FieldName n2 -> v2 -> Record2 n1 v1 n2 v2
--- 
--- We can set the name signatures by passing
--- proxies with explicit signatures to this lambda.
-conLambdaExp :: Int -> Maybe Exp
-conLambdaExp arity =
-  SigE <$> exp <*> t
-  where
-    exp =
-      LamE <$> pure pats <*> exp
-      where
-        pats =
-          concat $ flip map [1 .. arity] $ \i -> [WildP, VarP (mkName ("v" <> show i))]
-        exp =
-          foldl AppE <$> (ConE <$> recordConNameByArity arity) <*> 
-                         pure (map (\i -> VarE (mkName ("v" <> show i))) [1 .. arity])
-    t =
-      fnType <$> recordTypeNameByArity arity
-      where
-        fnType conName =
-          ForallT varBndrs [] $
-          foldr1 (\l r -> AppT (AppT ArrowT l) r)
-                 (argTypes <> pure (resultType conName))
-        varBndrs =
-          concat $ flip map [1 .. arity] $ \i ->
-            PlainTV (mkName ("n" <> show i)) :
-            PlainTV (mkName ("v" <> show i)) :
-            []
-        argTypes =
-          concat $ flip map [1 .. arity] $ \i -> 
-            AppT (ConT ''Types.FieldName) (VarT (mkName ("n" <> show i))) :
-            VarT (mkName ("v" <> show i)) :
-            []
-        resultType conName =
-          foldl AppT (ConT conName) $ concat $ flip map [1 .. arity] $ \i ->
-            VarT (mkName ("n" <> show i)) :
-            VarT (mkName ("v" <> show i)) :
-            []
-
+-- * Record construction functions with field names
+-------------------------
 
+-- Generate the function declarations:
+return $ concat $ TH.recordConFunDecs <$> [False, True] <*> [1 .. 24]
diff --git a/library/Record/Lens.hs b/library/Record/Lens.hs
deleted file mode 100644
--- a/library/Record/Lens.hs
+++ /dev/null
@@ -1,40 +0,0 @@
--- |
--- A minimal subset of the "lens" library functionality,
--- which is completely compatible with it.
--- 
--- Unless you use the "lens" library itself, 
--- this module is your interface to manipulating the record fields.
-module Record.Lens where
-
-import BasePrelude
-import Data.Functor.Identity
-
-
--- |
--- A reference from a datastructure @s@ to its some part @a@,
--- which can be used to manipulate that particular part.
--- It is possible to change the part to another type @a'@ during updates.
--- In such case the whole datastructure will change the type to @s'@ as well.
-type Lens s s' a a' = 
-  forall f. Functor f => (a -> f a') -> (s -> f s')
-
--- |
--- Given a lens to a subpart and a datastructure,
--- produce the value of the referred subpart.
-view :: Lens s s' a a' -> s -> a
-view l =
-  getConst . l Const
-
--- |
--- Given a lens to a subpart, a new value for it and a datastructure,
--- produce an updated datastructure.
-set :: Lens s s' a a' -> a' -> s -> s'
-set l a =
-  runIdentity . l (Identity . const a)
-
--- |
--- Given a lens to a subpart, and an update function for it,
--- produce a function, which updates the datastructure.
-over :: Lens s s' a a' -> (a -> a') -> s -> s'
-over l f =
-  runIdentity . l (Identity . f)
diff --git a/library/Record/Parser.hs b/library/Record/Parser.hs
deleted file mode 100644
--- a/library/Record/Parser.hs
+++ /dev/null
@@ -1,329 +0,0 @@
-module Record.Parser where
-
-import BasePrelude hiding (takeWhile, exp)
-import Data.Text (Text)
-import Data.Attoparsec.Text
-import qualified Data.Text as T
-
-
-data Type =
-  Type_App Type Type |
-  Type_Var Text |
-  Type_Con Ident |
-  Type_Tuple Int |
-  Type_Arrow |
-  Type_List |
-  Type_Record RecordType
-  deriving (Show)
-
-type QualifiedName =
-  [Text]
-
-type RecordType =
-  [(Text, Type)]
-
-
-run :: Parser a -> Text -> Either String a
-run p t =
-  onResult $ parse p t
-  where
-    onResult =
-      \case
-        Fail _ contexts message -> Left $ showString message . showString ". Contexts: " .
-                                          shows contexts $ "."
-        Done _ a -> Right a
-        Partial c -> onResult (c "")
-
--- |
--- Run a parser on a given input,
--- lifting its errors to the context parser.
---
--- Consider it a subparser.
-parser :: Parser a -> Text -> Parser a
-parser p t =
-  either fail return $
-  run p t
-
-labeled :: String -> Parser a -> Parser a
-labeled =
-  flip (<?>)
-
-qq :: Parser a -> Parser a
-qq p =
-  skipSpace *> p <* skipSpace <* endOfInput
-
--- |
--- >>> run type' "(Int, Char)"
--- Right (Type_App (Type_App (Type_Tuple 2) (Type_Con "Int")) (Type_Con "Char"))
---
--- >>> run type' "(,) Int Int"
--- Right (Type_App (Type_App (Type_Tuple 2) (Type_Con "Int")) (Type_Con "Int"))
---
--- >>> run type' "(,)"
--- Right (Type_Tuple 2)
---
--- >>> run type' "()"
--- Right (Type_Tuple 0)
---
--- >>> run type' "Int -> Double"
--- Right (Type_App (Type_App Type_Arrow (Type_Con "Int")) (Type_Con "Double"))
---
--- >>> run type' "(->) Int Double"
--- Right (Type_App (Type_App Type_Arrow (Type_Con "Int")) (Type_Con "Double"))
---
--- >>> run type' "A -> B -> C"
--- Right (Type_App (Type_App Type_Arrow (Type_Con "A")) (Type_App (Type_App Type_Arrow (Type_Con "B")) (Type_Con "C")))
-type' :: Parser Type
-type' =
-  labeled "type'" $
-  appArrowType <|> appType
-  where
-    -- Matches "appType -> (type)+"
-    -- Note the right associativity of the arrow operator.
-    appArrowType = do
-      t <- appType
-      skipMany1 space
-      a <- arrowType
-      skipMany1 space
-      t' <- type'
-      return $ Type_App (Type_App a t) t'
-    -- Corresponds to GHC's "btype" rule
-    -- Matches either two or more types and "App"s them,
-    -- or a single type.
-    appType =
-      (foldl1 Type_App <$>
-      sepBy1 nonAppType (skipMany1 space))
-      <|> nonAppType
-    -- Corresponds to GHC's "atype" rule
-    nonAppType =
-      arrowTypeCon <|> conType <|> tupleConType <|> tupleType <|> listConType <|> listType <|>
-      varType <|> (Type_Record <$> recordType) <|> inBraces type'
-    varType =
-      fmap Type_Var $ lowerCaseName
-    conType =
-      fmap Type_Con $ upperCaseIdent
-    tupleConType =
-      Type_Tuple 0 <$ string "()" <|>
-      Type_Tuple . succ . length <$> (char '(' *> many (char ',') <* char ')')
-    tupleType =
-      do
-        char '('
-        skipSpace
-        h <- type' <* skipSpace <* char ',' <* skipSpace
-        t <- sepBy1 type' (skipSpace *> char ',' <* skipSpace)
-        skipSpace
-        char ')'
-        return $ foldl Type_App (Type_Tuple (1 + length t)) $ h : t
-    listType =
-      fmap (Type_App Type_List) $
-        char '[' *> skipSpace *> type' <* skipSpace <* char ']'
-    listConType =
-      Type_List <$ string "[]"
-    arrowTypeCon =
-      Type_Arrow <$ string "(->)"
-    arrowType =
-      Type_Arrow <$ string "->"
-
-recordType :: Parser RecordType
-recordType =
-  labeled "recordType" $
-    char '{' *> skipSpace *> sepBy1' field (skipSpace *> char ',' <* skipSpace) <* skipSpace <* char '}'
-  where
-    field =
-      (,) <$> (lowerCaseName <* skipSpace <* string "::" <* skipSpace) <*> type'
-
-qualifiedName1 :: Parser QualifiedName
-qualifiedName1 =
-  ((\a b -> a <> pure b) <$> many1 (upperCaseName <* char '.') <*> lowerCaseName) <|>
-  (pure <$> lowerCaseName)
-
-inBraces :: Parser a -> Parser a
-inBraces p =
-  char '(' *> skipSpace *> p <* skipSpace <* char ')'
-
-lowerCaseName :: Parser Text
-lowerCaseName =
-  labeled "lowerCaseName" $
-    T.cons <$>
-      satisfy (\c -> isLower c || c == '_') <*>
-      takeWhile (\c -> isAlphaNum c || c == '\'' || c == '_')
-
-upperCaseName :: Parser Text
-upperCaseName =
-  labeled "upperCaseName" $
-    T.cons <$>
-      satisfy (\c -> isUpper c || c == '_') <*>
-      takeWhile (\c -> isAlphaNum c || c == '\'' || c == '_')
-
-symbolicIdent :: Parser Text
-symbolicIdent =
-  labeled "symbolicIdent" $
-    (\t -> "(" <> t <> ")") <$> (char '(' *> takeWhile1 isSymbol <* char ')')
-  where
-    isSymbol =
-      flip elem ("!#$%&*+./<=>?@\\^|-~" :: [Char])
-
-stringLit :: Parser Text
-stringLit =
-  quoted '"'
-  where
-    quoted q =
-      T.pack <$> (char q *> content <* char q)
-      where
-        content =
-          many char'
-          where
-            char' =
-              (char '\\' *> (char q <|> char '\\')) <|>
-              (notChar q)
-
-charLit :: Parser Char
-charLit =
-  char '\'' *> ((char '\\' *> (char '\'' <|> char '\\')) <|> notChar '\'') <* char '\''
-
-type Ident =
-  Text
-
-lowerCaseIdent :: Parser Ident
-lowerCaseIdent =
-  labeled "lowerCaseIdent" $
-  fmap (T.intercalate ".") $
-    (<>) <$>
-      (many (upperCaseName <* char '.')) <*>
-      (pure <$> (lowerCaseName <|> symbolicIdent))
-
-upperCaseIdent :: Parser Ident
-upperCaseIdent =
-  labeled "upperCaseIdent" $
-  fmap (T.intercalate ".") $
-    (<>) <$>
-      (many (upperCaseName <* char '.')) <*>
-      (pure <$> (upperCaseName <|> symbolicIdent))
-
-
-type Lens =
-  [Text]
-
-lens :: Parser Lens
-lens =
-  labeled "lens" $
-    sepBy1 (lowerCaseName <|> takeWhile1 isDigit) (char '.')
-
-
-data Exp =
-  Exp_Record RecordExp |
-  Exp_Var Ident |
-  Exp_Con Ident |
-  Exp_TupleCon Int |
-  Exp_Nil |
-  Exp_Lit Lit |
-  Exp_App Exp Exp |
-  Exp_List [Exp] |
-  Exp_Sig Exp Type
-  deriving (Show)
-
-type RecordExp =
-  [(Text, Exp)]
-
-data Lit =
-  Lit_Char Char |
-  Lit_String Text |
-  Lit_Integer Integer |
-  Lit_Rational Rational
-  deriving (Show)
-
--- |
---
--- >>> run exp "(,)"
--- Right (Exp_TupleCon 2)
---
--- >>> run exp "(1,2)"
--- Right (Exp_App (Exp_App (Exp_TupleCon 2) (Exp_Lit (Lit_Integer 1))) (Exp_Lit (Lit_Integer 2)))
---
--- >>> run exp "(1)"
--- Right (Exp_Lit (Lit_Integer 1))
---
--- >>> run exp "()"
--- Right (Exp_TupleCon 0)
-exp :: Parser Exp
-exp =
-  labeled "exp" $
-    sig <|> nonSig
-  where
-    sig =
-      Exp_Sig <$> nonSig <*> (skipSpace *> string "::" *> skipSpace *> type')
-    nonSig =
-      app <|> nonApp
-      where
-        app =
-          fmap (foldl1 Exp_App) $
-          sepBy1 nonApp (skipMany1 space)
-        nonApp =
-          record <|>
-          var <|>
-          con <|>
-          tupleCon <|>
-          nil <|>
-          Exp_Lit <$> lit <|>
-          tuple <|>
-          list <|>
-          inBraces exp
-          where
-            record =
-              Exp_Record <$> (char '{' *> skipSpace *> fields <* skipSpace <* char '}')
-              where
-                fields =
-                  sepBy1 field (skipSpace *> char ',' <* skipSpace)
-                  where
-                    field =
-                      (,) <$> lowerCaseName <*> (skipSpace *> char '=' *> skipSpace *> exp)
-            var =
-              Exp_Var <$> lowerCaseIdent
-            con =
-              Exp_Con <$> upperCaseIdent
-            tupleCon =
-              Exp_TupleCon 0 <$ string "()" <|>
-              Exp_TupleCon . succ . length <$> (char '(' *> many (char ',') <* char ')')
-            nil =
-              Exp_Nil <$ string "[]"
-            tuple =
-              do
-                char '('
-                skipSpace
-                h <- exp <* skipSpace <* char ',' <* skipSpace
-                t <- sepBy1 exp (skipSpace *> char ',' <* skipSpace)
-                skipSpace
-                char ')'
-                return $ foldl Exp_App (Exp_TupleCon (1 + length t)) $ h : t
-            list =
-              fmap Exp_List $
-                char '[' *> skipSpace *>
-                  sepBy1 exp (skipSpace *> char ',' <* skipSpace) <*
-                  skipSpace <* char ']'
-
--- |
---
--- Integers get parsed as integers:
---
--- >>> run lit "2"
--- Right (Lit_Integer 2)
---
--- Rationals get parsed as rationals:
---
--- >>> run lit "2.0"
--- Right (Lit_Rational (2 % 1))
---
--- >>> run lit "3e2"
--- Right (Lit_Rational (300 % 1))
-lit :: Parser Lit
-lit =
-  Lit_Char <$> charLit <|>
-  Lit_String <$> stringLit <|>
-  Lit_Rational <$> rationalNotDecimal <|>
-  Lit_Integer <$> decimal
-  where
-    rationalNotDecimal =
-      match rational >>= \(t, r) ->
-        case run (decimal <* endOfInput) t of
-          Left _ -> return r
-          _ -> mzero
diff --git a/library/Record/TH.hs b/library/Record/TH.hs
new file mode 100644
--- /dev/null
+++ b/library/Record/TH.hs
@@ -0,0 +1,253 @@
+{-# LANGUAGE CPP #-}
+module Record.TH where
+
+import BasePrelude hiding (Proxy)
+import GHC.TypeLits
+import Language.Haskell.TH hiding (classP)
+
+
+classP :: Name -> [Type] -> Pred
+#if MIN_VERSION_template_haskell(2,10,0)
+classP n tl = foldl AppT (ConT n) tl
+#else
+classP = ClassP
+#endif
+
+recordTypeDec :: Bool -> Int -> Dec
+recordTypeDec strict arity =
+  DataD [] name varBndrs [NormalC name conTypes] derivingNames
+  where
+    name =
+      recordName strict arity
+    varBndrs =
+      do
+        i <- [1 .. arity]
+        let
+          n = KindedTV (mkName ("n" <> show i)) (ConT ''Symbol)
+          v = PlainTV (mkName ("v" <> show i))
+          in [n, v]
+    conTypes =
+      do
+        i <- [1 .. arity]
+        return $ (,) strictness (VarT (mkName ("v" <> show i)))
+      where
+        strictness =
+          if strict then IsStrict else NotStrict
+    derivingNames =
+#if MIN_VERSION_base(4,7,0)
+      [''Show, ''Eq, ''Ord, ''Typeable, ''Generic]
+#else
+      [''Show, ''Eq, ''Ord, ''Generic]
+#endif
+
+recordName :: Bool -> Int -> Name
+recordName strict arity =
+  mkName $ recordNameString strict arity
+
+recordNameString :: Bool -> Int -> String
+recordNameString strict arity =
+  prefix <> "Record" <> show arity
+  where
+    prefix =
+      if strict then "Strict" else "Lazy"
+
+recordFieldInstanceDec :: Bool -> Int -> Int -> Dec
+recordFieldInstanceDec strict =
+  fieldInstanceDec (FieldInstanceDecMode_Record strict)
+
+tupleFieldInstanceDec :: Int -> Int -> Dec
+tupleFieldInstanceDec arity fieldIndex =
+  fieldInstanceDec FieldInstanceDecMode_Tuple arity fieldIndex
+
+data FieldInstanceDecMode =
+  FieldInstanceDecMode_Tuple |
+  FieldInstanceDecMode_Record Bool
+
+fieldInstanceDec :: FieldInstanceDecMode -> Int -> Int -> Dec
+fieldInstanceDec mode arity fieldIndex =
+  InstanceD [] headType decs
+  where
+    headType =
+      foldl1 AppT 
+      [classType, VarT selectedNVarName, recordType, recordPrimeType, VarT selectedVVarName, VarT selectedVPrimeVarName]
+      where
+        classType =
+          ConT (mkName "Field")
+    typeName =
+      case mode of
+        FieldInstanceDecMode_Tuple -> tupleTypeName arity
+        FieldInstanceDecMode_Record strict -> recordName strict arity
+    conName =
+      case mode of
+        FieldInstanceDecMode_Tuple -> tupleDataName arity
+        FieldInstanceDecMode_Record strict -> recordName strict arity
+    selectedNVarName =
+      mkName $ "n" <> show fieldIndex
+    selectedVVarName =
+      mkName $ "v" <> show fieldIndex
+    selectedVPrimeVarName =
+      mkName $ "v" <> show fieldIndex <> "'"
+    recordType =
+      foldl (\a i -> AppT (addNVar a i)
+                          (VarT (mkName ("v" <> show i))))
+            (ConT typeName)
+            [1 .. arity]
+    recordPrimeType =
+      foldl (\a i -> AppT (addNVar a i)
+                          (VarT (if i == fieldIndex then selectedVPrimeVarName
+                                                    else mkName ("v" <> show i))))
+            (ConT typeName)
+            [1 .. arity]
+    addNVar =
+      case mode of
+        FieldInstanceDecMode_Tuple -> \a i -> a
+        FieldInstanceDecMode_Record _ -> \a i -> AppT a (VarT (mkName ("n" <> show i)))
+    decs =
+      [fieldLensDec]
+      where
+        fieldLensDec =
+          FunD (mkName "fieldLens") [Clause patterns (NormalB exp) []]
+          where
+            patterns =
+              [WildP, VarP fVarName, ConP conName (fmap VarP indexedVVarNames)]
+            fVarName =
+              mkName "f"
+            indexedVVarNames =
+              fmap (\i -> mkName ("v" <> show i)) [1..arity]
+            exp =
+              AppE (AppE (VarE 'fmap) (consLambda))
+                   (AppE (VarE fVarName) (VarE selectedVVarName))
+              where
+                consLambda =
+                  LamE [VarP selectedVPrimeVarName] exp
+                  where
+                    exp =
+                      foldl AppE (ConE conName) $
+                      map VarE $
+                      map (\(i, n) -> if i == fieldIndex then selectedVPrimeVarName
+                                                         else mkName ("v" <> show i)) $
+                      zip [1 .. arity] indexedVVarNames
+
+recordStorableInstanceDec :: Bool -> Int -> Dec
+recordStorableInstanceDec strict arity =
+  InstanceD context (AppT (ConT (mkName "Storable")) recordType)
+            [sizeOfFun, inlineFun "sizeOf", alignmentFun, inlineFun "alignment"
+            , peekFun, inlineFun "peek", pokeFun, inlineFun "poke"]
+  where
+    name = recordName strict arity
+    recordType =
+      foldl (\a i -> AppT (AppT a (VarT (mkName ("n" <> show i))))
+                          (VarT (mkName ("v" <> show i))))
+            (ConT name)
+            [1 .. arity]
+    context = map (\i -> classP (mkName "Storable")  [VarT (mkName ("v" <> show i))])
+              [1 .. arity]
+    nameE = VarE . mkName
+    -- The sum of the sizes of all types
+    sizeOfFun' n = foldr (\a b -> AppE (AppE (nameE "+") a) b) (LitE (IntegerL 0)) $
+                   map (\i -> AppE
+                              (nameE "sizeOf")
+                              (SigE (nameE "undefined")
+                                    (VarT (mkName ("v" <> show i)))))
+                   [1..n]
+    sizeOfFun = FunD (mkName "sizeOf")
+                [Clause [WildP]
+                 (NormalB (sizeOfFun' arity)) []]
+    -- Set the alignment to the maximum alignment of the types
+    alignmentFun = FunD (mkName "alignment")
+                   [(Clause [WildP]
+                     (NormalB (AppE (nameE "maximum") $ ListE $
+                               map (\i -> AppE
+                                          (nameE "sizeOf")
+                                          (SigE (nameE "undefined")
+                                                (VarT (mkName ("v" <> show i)))))
+                               [1..arity])) [])]
+    -- Peek every variable, remember to add the size of the elements already seen to the ptr
+    peekFun = FunD (mkName "peek")
+              [(Clause [VarP (mkName "ptr")]
+                  (NormalB (DoE $ map (\i -> BindS
+                                             (BangP (VarP (mkName ("x" <> show i))))
+                                                    (AppE (nameE "peek")
+                                                          (AppE (AppE (nameE "plusPtr")
+                                                                      (nameE "ptr"))
+                                                                (sizeOfFun' (i - 1))))) [1..arity]
+                                 ++ [NoBindS (AppE (nameE "return")
+                                             (foldl (\a i -> AppE a (nameE ("x" <> show i)))
+                                             (ConE name) [1 .. arity]))])) [])]
+    typePattern = ConP name (map (\i -> VarP (mkName ("v" <> show i))) [1..arity])
+    pokeFun = FunD (mkName "poke")
+              [(Clause [VarP (mkName "ptr"), typePattern]
+                 (NormalB (DoE $ map (\i -> NoBindS
+                                            (AppE
+                                             (AppE (VarE (mkName "poke"))
+                                                   (AppE (AppE (nameE "plusPtr")
+                                                                 (nameE "ptr"))
+                                                          (sizeOfFun' (i - 1))))
+                                             (nameE ("v" <> show i)))) [1..arity])) [])]
+    inlineFun name = PragmaD $ InlineP (mkName name) Inline FunLike AllPhases
+
+recordConFunDecs :: Bool -> Int -> [Dec]
+recordConFunDecs strict arity =
+  [inline, fun]
+  where
+    inline =
+      PragmaD (InlineP name Inline FunLike AllPhases)
+    fun =
+      FunD name [Clause [] (NormalB (recordConLambdaExp strict arity)) []]
+    name =
+      mkName string
+      where
+        string =
+          onHead toLower (recordNameString strict arity)
+          where
+            onHead f =
+              \case
+                a : b -> f a : b
+                [] -> []
+
+-- |
+-- Allows to specify field names at value-level.
+-- Useful for type-inference.
+-- 
+-- E.g., in
+-- 
+-- >(\_ v1 _ v2 -> StrictRecord2 v1 v2) :: Types.FieldName n1 -> v1 -> Types.FieldName n2 -> v2 -> StrictRecord2 n1 v1 n2 v2
+-- 
+-- we can set the name signatures by passing
+-- the name-proxies to this lambda.
+recordConLambdaExp :: Bool -> Int -> Exp
+recordConLambdaExp strict arity =
+  SigE exp t
+  where
+    name =
+      recordName strict arity
+    exp =
+      LamE pats exp
+      where
+        pats =
+          concat $ flip map [1 .. arity] $ \i -> [WildP, VarP (mkName ("v" <> show i))]
+        exp =
+          foldl AppE (ConE name) (map (\i -> VarE (mkName ("v" <> show i))) [1 .. arity])
+    t =
+      fnType name
+      where
+        fnType conName =
+          ForallT varBndrs [] $
+          foldr1 (\l r -> AppT (AppT ArrowT l) r)
+                 (argTypes <> pure (resultType conName))
+        varBndrs =
+          concat $ flip map [1 .. arity] $ \i ->
+            PlainTV (mkName ("n" <> show i)) :
+            PlainTV (mkName ("v" <> show i)) :
+            []
+        argTypes =
+          concat $ flip map [1 .. arity] $ \i -> 
+            AppT (ConT (mkName "FieldName")) (VarT (mkName ("n" <> show i))) :
+            VarT (mkName ("v" <> show i)) :
+            []
+        resultType conName =
+          foldl AppT (ConT conName) $ concat $ flip map [1 .. arity] $ \i ->
+            VarT (mkName ("n" <> show i)) :
+            VarT (mkName ("v" <> show i)) :
+            []
+
diff --git a/library/Record/Types.hs b/library/Record/Types.hs
deleted file mode 100644
--- a/library/Record/Types.hs
+++ /dev/null
@@ -1,272 +0,0 @@
-{-# LANGUAGE CPP, UndecidableInstances #-}
--- |
--- The contents of this module may seem a bit overwhelming.
--- Don't worry,
--- all it does is just cover instances and datatypes of records and tuples of
--- huge arities.
---
--- You don't actually need to ever use this module,
--- since all the functionality you may need is presented
--- by the quasiquoters exported in the root module.
-module Record.Types where
-
-import BasePrelude hiding (Proxy)
-import Data.Functor.Identity
-import GHC.TypeLits
-import Record.Lens (Lens)
-import Language.Haskell.TH
-import Foreign.Storable
-import Foreign.Ptr (plusPtr)
-import qualified TemplateHaskell.Compat.V0208 as A
-
-
--- *
--------------------------
-
-
--- |
--- Defines a lens to manipulate some value of a type by a type-level name,
--- using the string type literal functionality.
---
--- Instances are provided for all records and for tuples of arity of up to 24.
---
--- Here's how you can use it with tuples:
---
--- >trd :: Field "3" v v' a' a => a -> v
--- >trd = view . fieldLens (undefined :: FieldName "3")
--- The function above will get you the third item of any tuple, which has it.
-class Field (n :: Symbol) a a' v v' | n a -> v, n a' -> v', n a v' -> a', n a' v -> a where
-  -- |
-  -- A polymorphic lens. E.g.:
-  --
-  -- >ageLens :: Field "age" v v' a' a => Lens a a' v v'
-  -- >ageLens = fieldLens (undefined :: FieldName "age")
-  fieldLens :: FieldName n -> Lens a a' v v'
-
--- |
--- A simplified field constraint,
--- which excludes the possibility of type-changing updates.
-type Field' n a v =
-  Field n a a v v
-
--- |
--- A specialised version of "Data.Proxy.Proxy".
--- Defined for compatibility with \"base-4.6\",
--- since @Proxy@ was only defined in \"base-4.7\".
-data FieldName (t :: Symbol)
-
-
--- * Record Types
--------------------------
-
--- Generate Record types
-return $ flip map [1 .. 24] $ \arity ->
-  let
-    typeName =
-      mkName $ "Record" <> show arity
-    varBndrs =
-      do
-        i <- [1 .. arity]
-        let
-          n = KindedTV (mkName ("n" <> show i)) (ConT ''Symbol)
-          v = PlainTV (mkName ("v" <> show i))
-          in [n, v]
-    conTypes =
-      do
-        i <- [1 .. arity]
-        return $ (,) (A.notStrict) (VarT (mkName ("v" <> show i)))
-    derivingNames =
-#if MIN_VERSION_base(4,7,0)
-      [''Show, ''Eq, ''Ord, ''Typeable, ''Generic]
-#else
-      [''Show, ''Eq, ''Ord, ''Generic]
-#endif
-    in
-      A.dataD [] typeName varBndrs [NormalC typeName conTypes] derivingNames
-
-
--- Generate instances of Foreign.Storable
-return $ flip map [1 .. 24] $ \arity ->
-  let
-    typeName = mkName $ "Record" <> show arity
-    recordType =
-      foldl (\a i -> AppT (AppT a (VarT (mkName ("n" <> show i))))
-                          (VarT (mkName ("v" <> show i))))
-            (ConT typeName)
-            [1 .. arity]
-#if MIN_VERSION_template_haskell(2,10,0)
-    -- In TH with `ConstraintKinds` the context is just simply a type
-    context = map (\i -> AppT (ConT (mkName "Storable")) (VarT (mkName ("v" <> show i))))
-              [1 .. arity]
-#else
-    context = map (\i -> ClassP (mkName "Storable")  [VarT (mkName ("v" <> show i))])
-              [1 .. arity]
-#endif
-    nameE = VarE . mkName
-    -- The sum of the sizes of all types
-    sizeOfFun' n = foldr (\a b -> AppE (AppE (nameE "+") a) b) (LitE (IntegerL 0)) $
-                   map (\i -> AppE
-                              (nameE "sizeOf")
-                              (SigE (nameE "undefined")
-                                    (VarT (mkName ("v" <> show i)))))
-                   [1..n]
-    sizeOfFun = FunD (mkName "sizeOf")
-                [Clause [WildP]
-                 (NormalB (sizeOfFun' arity)) []]
-    -- Set the alignment to the maximum alignment of the types
-    alignmentFun = FunD (mkName "alignment")
-                   [(Clause [WildP]
-                     (NormalB (AppE (nameE "maximum") $ ListE $
-                               map (\i -> AppE
-                                          (nameE "sizeOf")
-                                          (SigE (nameE "undefined")
-                                                (VarT (mkName ("v" <> show i)))))
-                               [1..arity])) [])]
-    -- Peek every variable, remember to add the size of the elements already seen to the ptr
-    peekFun = FunD (mkName "peek")
-              [(Clause [VarP (mkName "ptr")]
-                  (NormalB (DoE $ map (\i -> BindS
-                                             (BangP (VarP (mkName ("x" <> show i))))
-                                                    (AppE (nameE "peek")
-                                                          (AppE (AppE (nameE "plusPtr")
-                                                                      (nameE "ptr"))
-                                                                (sizeOfFun' (i - 1))))) [1..arity]
-                                 ++ [NoBindS (AppE (nameE "return")
-                                             (foldl (\a i -> AppE a (nameE ("x" <> show i)))
-                                             (ConE typeName) [1 .. arity]))])) [])]
-    typePattern = ConP typeName (map (\i -> VarP (mkName ("v" <> show i))) [1..arity])
-    pokeFun = FunD (mkName "poke")
-              [(Clause [VarP (mkName "ptr"), typePattern]
-                 (NormalB (DoE $ map (\i -> NoBindS
-                                            (AppE
-                                             (AppE (VarE (mkName "poke"))
-                                                   (AppE (AppE (nameE "plusPtr")
-                                                                 (nameE "ptr"))
-                                                          (sizeOfFun' (i - 1))))
-                                             (nameE ("v" <> show i)))) [1..arity])) [])]
-    inlineFun name = PragmaD $ InlineP (mkName name) Inline FunLike AllPhases
-  in
-    A.instanceD context (AppT (ConT (mkName "Storable")) recordType)
-                [sizeOfFun, inlineFun "sizeOf", alignmentFun, inlineFun "alignment"
-                , peekFun, inlineFun "peek", pokeFun, inlineFun "poke"]
-
--- *
--------------------------
-
-return $ do
-  arity <- [1 .. 24]
-  nIndex <- [1 .. arity]
-  return $
-    let
-      typeName =
-        mkName $ "Record" <> show arity
-      selectedNVarName =
-        mkName $ "n" <> show nIndex
-      selectedVVarName =
-        mkName $ "v" <> show nIndex
-      selectedV'VarName =
-        mkName $ "v" <> show nIndex <> "'"
-      recordType =
-        foldl (\a i -> AppT (AppT a (VarT (mkName ("n" <> show i))))
-                            (VarT (mkName ("v" <> show i))))
-              (ConT typeName)
-              [1 .. arity]
-      record'Type =
-        foldl (\a i -> AppT (AppT a (VarT (mkName ("n" <> show i))))
-                            (VarT (if i == nIndex then selectedV'VarName
-                                                  else mkName ("v" <> show i))))
-              (ConT typeName)
-              [1 .. arity]
-      fieldLensLambda =
-        LamE [VarP fVarName, ConP typeName (fmap VarP indexedVVarNames)] exp
-        where
-          fVarName =
-            mkName "f"
-          indexedVVarNames =
-            fmap (\i -> mkName ("v" <> show i)) [1..arity]
-          exp =
-            AppE (AppE (VarE 'fmap) (consLambda))
-                 (AppE (VarE fVarName) (VarE selectedVVarName))
-            where
-              consLambda =
-                LamE [VarP selectedV'VarName] exp
-                where
-                  exp =
-                    foldl AppE (ConE typeName) $
-                    map VarE $
-                    map (\(i, n) -> if i == nIndex then selectedV'VarName
-                                                   else mkName ("v" <> show i)) $
-                    zip [1 .. arity] indexedVVarNames
-      in
-        head $ unsafePerformIO $ runQ $
-        [d|
-          instance Field $(varT selectedNVarName)
-                         $(pure recordType)
-                         $(pure record'Type)
-                         $(varT selectedVVarName)
-                         $(varT selectedV'VarName)
-                         where
-            {-# INLINE fieldLens #-}
-            fieldLens = const $(pure fieldLensLambda)
-        |]
-
-
-instance Field "1" (Identity v1) (Identity v1') v1 v1' where
-  fieldLens = const $ \f -> fmap Identity . f . runIdentity
-
-
--- Generate Field instances for tuples
-return $ do
-  arity <- [2 .. 24]
-  nIndex <- [1 .. arity]
-  return $
-    let
-      typeName =
-        tupleTypeName arity
-      conName =
-        tupleDataName arity
-      selectedVVarName =
-        mkName $ "v" <> show nIndex
-      selectedV'VarName =
-        mkName $ "v" <> show nIndex <> "'"
-      tupleType =
-        foldl (\a i -> AppT a (VarT (mkName ("v" <> show i))))
-              (ConT typeName)
-              [1 .. arity]
-      tuple'Type =
-        foldl (\a i -> AppT a (VarT (if i == nIndex then selectedV'VarName
-                                                    else mkName ("v" <> show i))))
-              (ConT typeName)
-              [1 .. arity]
-      fieldLensLambda =
-        LamE [VarP fVarName, ConP conName (fmap VarP indexedVVarNames)] exp
-        where
-          fVarName =
-            mkName "f"
-          indexedVVarNames =
-            fmap (\i -> mkName ("v" <> show i)) [1..arity]
-          exp =
-            AppE (AppE (VarE 'fmap) (consLambda))
-                 (AppE (VarE fVarName) (VarE selectedVVarName))
-            where
-              consLambda =
-                LamE [VarP selectedV'VarName] exp
-                where
-                  exp =
-                    foldl AppE (ConE conName) $
-                    map VarE $
-                    map (\(i, n) -> if i == nIndex then selectedV'VarName
-                                                   else mkName ("v" <> show i)) $
-                    zip [1 .. arity] indexedVVarNames
-      in
-        head $ unsafePerformIO $ runQ $
-        [d|
-          instance Field $(pure (LitT (StrTyLit (show nIndex))))
-                         $(pure tupleType)
-                         $(pure tuple'Type)
-                         $(varT selectedVVarName)
-                         $(varT selectedV'VarName)
-                         where
-            {-# INLINE fieldLens #-}
-            fieldLens = const $(pure fieldLensLambda)
-        |]
diff --git a/record.cabal b/record.cabal
--- a/record.cabal
+++ b/record.cabal
@@ -1,21 +1,16 @@
 name:
   record
 version:
-  0.3.2.1
+  0.4.0.0
 synopsis:
-  First class records implemented with quasi-quotation
+  Anonymous records
 description:
-  An API of just two quasi-quoters, 
-  providing a full-scale solution to the notorious records problem of Haskell.
-  .
-  Links:
-  .
-  * <http://nikita-volkov.github.io/record A comprehensive introduction to the library>.
-  .
-  * <https://github.com/nikita-volkov/record/blob/master/demo/Main.hs Demo>.
-  .
+  This library provides the abstractions behind the anonymous record syntax.
+  It is intended to be used in conjunction with
+  <http://hackage.haskell.org/package/record-preprocessor the "record-preprocessor">,
+  which enables a Haskell syntax extension.
 category:
-  Control, Data Structures
+  Control, Data Structures, Records
 homepage:
   https://github.com/nikita-volkov/record 
 bug-reports:
@@ -31,7 +26,7 @@
 license-file:
   LICENSE
 build-type:
-  Custom
+  Simple
 cabal-version:
   >=1.10
 extra-source-files:
@@ -45,82 +40,21 @@
     git://github.com/nikita-volkov/record.git
 
 
-flag doctest
-  description: Build Doctests
-  default: True
-  manual: True
-
-
 library
   hs-source-dirs:
     library
-  ghc-options:
-    -funbox-strict-fields
   default-extensions:
-    Arrows, BangPatterns, ConstraintKinds, DataKinds, DefaultSignatures, DeriveDataTypeable, DeriveFoldable, DeriveFunctor, DeriveGeneric, DeriveTraversable, 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
+    Arrows, BangPatterns, ConstraintKinds, DataKinds, DefaultSignatures, DeriveDataTypeable, DeriveFunctor, DeriveGeneric, EmptyDataDecls, FlexibleContexts, FlexibleInstances, FunctionalDependencies, GADTs, GeneralizedNewtypeDeriving, ImpredicativeTypes, LambdaCase, LiberalTypeSynonyms, MagicHash, MultiParamTypeClasses, MultiWayIf, NoImplicitPrelude, NoMonomorphismRestriction, OverloadedStrings, PatternGuards, ParallelListComp, QuasiQuotes, RankNTypes, RecordWildCards, ScopedTypeVariables, StandaloneDeriving, TemplateHaskell, TupleSections, TypeFamilies, TypeOperators, UnboxedTuples
   default-language:
     Haskell2010
   other-modules:
-    Record.Parser
+    Record.TH
   exposed-modules:
-    Record.Types
-    Record.Lens
     Record
   build-depends:
     -- 
-    attoparsec >= 0.12 && < 0.14,
-    -- 
-    text >= 1 && < 2,
-    --
-    template-haskell >= 2.8 && < 3,
-    template-haskell-compat-v0208 >= 0.1.1.1 && < 0.2,
+    template-haskell == 2.*,
     -- 
-    transformers >= 0.2 && < 0.6,
-    base-prelude >= 0.1 && < 2,
-    base >= 4.6 && < 5
-
-
-test-suite doctest
-  type:
-    exitcode-stdio-1.0
-  hs-source-dirs:
-    doctest
-  main-is:
-    Main.hs
-  ghc-options:
-    -threaded
-    "-with-rtsopts=-N"
-    -funbox-strict-fields
-  default-extensions:
-    Arrows, BangPatterns, ConstraintKinds, DataKinds, DefaultSignatures, DeriveDataTypeable, DeriveFoldable, DeriveFunctor, DeriveGeneric, DeriveTraversable, 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
-  if !flag(doctest)
-    buildable: False
-  build-depends:
-    doctest >= 0.13 && < 0.17,
-    directory >= 1.2 && < 1.5,
-    filepath >= 1.3 && < 1.5,
-    base
-
-
--- Well, it's not a benchmark actually, 
--- but in Cabal there's no cleaner way to specify an executable, 
--- which is not intended for distribution.
-benchmark demo
-  type: 
-    exitcode-stdio-1.0
-  hs-source-dirs:
-    demo
-  main-is:
-    Main.hs
-  ghc-options:
-    -O2
-    -threaded
-    "-with-rtsopts=-N"
-    -funbox-strict-fields
-  default-language:
-    Haskell2010
-  build-depends:
-    record,
-    base-prelude
+    basic-lens == 0.0.*,
+    base-prelude >= 0.1 && < 0.2,
+    base >= 4.6 && < 4.9
