{-# LANGUAGE ConstraintKinds            #-}
{-# LANGUAGE DefaultSignatures          #-}
{-# LANGUAGE DeriveFunctor              #-}
{-# LANGUAGE DeriveGeneric              #-}
{-# LANGUAGE FlexibleInstances          #-}
{-# LANGUAGE FlexibleContexts           #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiWayIf                 #-}
{-# LANGUAGE OverloadedStrings          #-}
{-# LANGUAGE PolyKinds                  #-}
{-# LANGUAGE RankNTypes                 #-}
{-# LANGUAGE RecordWildCards            #-}
{-# LANGUAGE ScopedTypeVariables        #-}
{-# LANGUAGE StandaloneDeriving         #-}
{-# LANGUAGE TypeFamilies               #-}
{-# LANGUAGE TypeOperators              #-}
{-# LANGUAGE TupleSections              #-}
{-# LANGUAGE UndecidableInstances       #-}
module Dhall
    (
    
      input
    , inputWithSettings
    , inputFile
    , inputFileWithSettings
    , inputExpr
    , inputExprWithSettings
    , rootDirectory
    , sourceName
    , startingContext
    , normalizer
    , defaultInputSettings
    , InputSettings
    , defaultEvaluateSettings
    , EvaluateSettings
    , HasEvaluateSettings
    , detailed
    
    , Decoder (..)
    , RecordDecoder(..)
    , UnionDecoder(..)
    , Encoder(..)
    , FromDhall(..)
    , Interpret
    , InvalidDecoder(..)
    , ExtractErrors(..)
    , Extractor
    , MonadicExtractor
    , typeError
    , extractError
    , toMonadic
    , fromMonadic
    , auto
    , genericAuto
    , InterpretOptions(..)
    , SingletonConstructors(..)
    , defaultInterpretOptions
    , bool
    , natural
    , integer
    , scientific
    , double
    , lazyText
    , strictText
    , maybe
    , sequence
    , list
    , vector
    , function
    , setFromDistinctList
    , setIgnoringDuplicates
    , hashSetFromDistinctList
    , hashSetIgnoringDuplicates
    , Dhall.map
    , hashMap
    , pairFromMapEntry
    , unit
    , void
    , string
    , pair
    , record
    , field
    , union
    , constructor
    , GenericFromDhall(..)
    , GenericToDhall(..)
    , ToDhall(..)
    , Inject
    , inject
    , genericToDhall
    , RecordEncoder(..)
    , encodeFieldWith
    , encodeField
    , recordEncoder
    , UnionEncoder(..)
    , encodeConstructorWith
    , encodeConstructor
    , unionEncoder
    , (>|<)
    
    , rawInput
    , (>$<)
    , (>*<)
    
    , Natural
    , Seq
    , Text
    , Vector
    , Generic
    ) where
import Control.Applicative (empty, liftA2, Alternative)
import Control.Exception (Exception)
import Control.Monad.Trans.State.Strict
import Control.Monad (guard)
import Data.Coerce (coerce)
import Data.Either.Validation (Validation(..), ealt, eitherToValidation, validationToEither)
import Data.Fix (Fix(..))
import Data.Functor.Contravariant (Contravariant(..), (>$<), Op(..))
import Data.Functor.Contravariant.Divisible (Divisible(..), divided)
import Data.Hashable (Hashable)
import Data.List.NonEmpty (NonEmpty (..))
import Data.HashMap.Strict (HashMap)
import Data.Map (Map)
import Data.Monoid ((<>))
import Data.Scientific (Scientific)
import Data.Semigroup (Semigroup)
import Data.Sequence (Seq)
import Data.Text (Text)
import Data.Text.Prettyprint.Doc (Pretty)
import Data.Typeable (Typeable)
import Data.Vector (Vector)
import Data.Void (Void)
import Data.Word (Word8, Word16, Word32, Word64)
import Dhall.Syntax (Expr(..), Chunks(..), DhallDouble(..))
import Dhall.Import (Imported(..))
import Dhall.Parser (Src(..))
import Dhall.TypeCheck (DetailedTypeError(..), TypeError)
import GHC.Generics
import Lens.Family (LensLike', view)
import Numeric.Natural (Natural)
import Prelude hiding (maybe, sequence)
import System.FilePath (takeDirectory)
import qualified Control.Applicative
import qualified Control.Exception
import qualified Control.Monad.Trans.State.Strict as State
import qualified Data.Foldable
import qualified Data.Functor.Compose
import qualified Data.Functor.Product
import qualified Data.HashMap.Strict as HashMap
import qualified Data.Map
import qualified Data.Maybe
import qualified Data.List
import qualified Data.List.NonEmpty
import qualified Data.Semigroup
import qualified Data.Scientific
import qualified Data.Sequence
import qualified Data.Set
import qualified Data.HashSet
import qualified Data.Text
import qualified Data.Text.IO
import qualified Data.Text.Lazy
import qualified Data.Vector
import qualified Data.Void
import qualified Dhall.Context
import qualified Dhall.Core
import qualified Dhall.Import
import qualified Dhall.Map
import qualified Dhall.Parser
import qualified Dhall.Pretty.Internal
import qualified Dhall.TypeCheck
import qualified Dhall.Util
import qualified Lens.Family
type Extractor s a = Validation (ExtractErrors s a)
type MonadicExtractor s a = Either (ExtractErrors s a)
typeError :: Expr s a -> Expr s a -> Extractor s a b
typeError expected actual =
    Failure . ExtractErrors . pure . TypeMismatch $ InvalidDecoder expected actual
extractError :: Text -> Extractor s a b
extractError = Failure . ExtractErrors . pure . ExtractError
toMonadic :: Extractor s a b -> MonadicExtractor s a b
toMonadic = validationToEither
fromMonadic :: MonadicExtractor s a b -> Extractor s a b
fromMonadic = eitherToValidation
newtype ExtractErrors s a = ExtractErrors
   { getErrors :: NonEmpty (ExtractError s a)
   } deriving Semigroup
instance (Pretty s, Pretty a, Typeable s, Typeable a) => Show (ExtractErrors s a) where
    show (ExtractErrors (e :| [])) = show e
    show (ExtractErrors es) = prefix <> (unlines . Data.List.NonEmpty.toList . fmap show $ es)
      where
        prefix =
            "Multiple errors were encountered during extraction: \n\
            \                                                    \n"
instance (Pretty s, Pretty a, Typeable s, Typeable a) => Exception (ExtractErrors s a)
data ExtractError s a =
    TypeMismatch (InvalidDecoder s a)
  | ExtractError Text
instance (Pretty s, Pretty a, Typeable s, Typeable a) => Show (ExtractError s a) where
  show (TypeMismatch e)  = show e
  show (ExtractError es) =
      _ERROR <> ": Failed extraction                                                   \n\
      \                                                                                \n\
      \The expression type-checked successfully but the transformation to the target   \n\
      \type failed with the following error:                                           \n\
      \                                                                                \n\
      \" <> Data.Text.unpack es <> "\n\
      \                                                                                \n"
instance (Pretty s, Pretty a, Typeable s, Typeable a) => Exception (ExtractError s a)
data InvalidDecoder s a = InvalidDecoder
  { invalidDecoderExpected   :: Expr s a
  , invalidDecoderExpression :: Expr s a
  }
  deriving (Typeable)
instance (Pretty s, Typeable s, Pretty a, Typeable a) => Exception (InvalidDecoder s a)
_ERROR :: String
_ERROR = "\ESC[1;31mError\ESC[0m"
instance (Pretty s, Pretty a, Typeable s, Typeable a) => Show (InvalidDecoder s a) where
    show InvalidDecoder { .. } =
        _ERROR <> ": Invalid Dhall.Decoder                                               \n\
        \                                                                                \n\
        \Every Decoder must provide an extract function that succeeds if an expression   \n\
        \matches the expected type.  You provided a Decoder that disobeys this contract  \n\
        \                                                                                \n\
        \The Decoder provided has the expected dhall type:                               \n\
        \                                                                                \n\
        \" <> show txt0 <> "\n\
        \                                                                                \n\
        \and it couldn't extract a value from the well-typed expression:                 \n\
        \                                                                                \n\
        \" <> show txt1 <> "\n\
        \                                                                                \n"
        where
          txt0 = Dhall.Util.insert invalidDecoderExpected
          txt1 = Dhall.Util.insert invalidDecoderExpression
data InputSettings = InputSettings
  { _rootDirectory :: FilePath
  , _sourceName :: FilePath
  , _evaluateSettings :: EvaluateSettings
  }
defaultInputSettings :: InputSettings
defaultInputSettings = InputSettings
  { _rootDirectory = "."
  , _sourceName = "(input)"
  , _evaluateSettings = defaultEvaluateSettings
  }
rootDirectory
  :: (Functor f)
  => LensLike' f InputSettings FilePath
rootDirectory k s =
  fmap (\x -> s { _rootDirectory = x }) (k (_rootDirectory s))
sourceName
  :: (Functor f)
  => LensLike' f InputSettings FilePath
sourceName k s =
  fmap (\x -> s { _sourceName = x}) (k (_sourceName s))
data EvaluateSettings = EvaluateSettings
  { _startingContext :: Dhall.Context.Context (Expr Src Void)
  , _normalizer      :: Maybe (Dhall.Core.ReifiedNormalizer Void)
  }
defaultEvaluateSettings :: EvaluateSettings
defaultEvaluateSettings = EvaluateSettings
  { _startingContext = Dhall.Context.empty
  , _normalizer      = Nothing
  }
startingContext
  :: (Functor f, HasEvaluateSettings s)
  => LensLike' f s (Dhall.Context.Context (Expr Src Void))
startingContext = evaluateSettings . l
  where
    l :: (Functor f)
      => LensLike' f EvaluateSettings (Dhall.Context.Context (Expr Src Void))
    l k s = fmap (\x -> s { _startingContext = x}) (k (_startingContext s))
normalizer
  :: (Functor f, HasEvaluateSettings s)
  => LensLike' f s (Maybe (Dhall.Core.ReifiedNormalizer Void))
normalizer = evaluateSettings . l
  where
    l :: (Functor f)
      => LensLike' f EvaluateSettings (Maybe (Dhall.Core.ReifiedNormalizer Void))
    l k s = fmap (\x -> s { _normalizer = x }) (k (_normalizer s))
class HasEvaluateSettings s where
  evaluateSettings
    :: (Functor f)
    => LensLike' f s EvaluateSettings
instance HasEvaluateSettings InputSettings where
  evaluateSettings k s =
    fmap (\x -> s { _evaluateSettings = x }) (k (_evaluateSettings s))
instance HasEvaluateSettings EvaluateSettings where
  evaluateSettings = id
input
    :: Decoder a
    
    -> Text
    
    -> IO a
    
input =
  inputWithSettings defaultInputSettings
inputWithSettings
    :: InputSettings
    -> Decoder a
    
    -> Text
    
    -> IO a
    
inputWithSettings settings (Decoder {..}) txt = do
    expr  <- Dhall.Core.throws (Dhall.Parser.exprFromText (view sourceName settings) txt)
    let InputSettings {..} = settings
    let EvaluateSettings {..} = _evaluateSettings
    let transform =
               Lens.Family.set Dhall.Import.normalizer      _normalizer
            .  Lens.Family.set Dhall.Import.startingContext _startingContext
    let status = transform (Dhall.Import.emptyStatus _rootDirectory)
    expr' <- State.evalStateT (Dhall.Import.loadWith expr) status
    let suffix = Dhall.Pretty.Internal.prettyToStrictText expected
    let annot = case expr' of
            Note (Src begin end bytes) _ ->
                Note (Src begin end bytes') (Annot expr' expected)
              where
                bytes' = bytes <> " : " <> suffix
            _ ->
                Annot expr' expected
    _ <- Dhall.Core.throws (Dhall.TypeCheck.typeWith (view startingContext settings) annot)
    let normExpr = Dhall.Core.normalizeWith (view normalizer settings) expr'
    case extract normExpr  of
        Success x  -> return x
        Failure e -> Control.Exception.throwIO e
inputFile
  :: Decoder a
  
  -> FilePath
  
  -> IO a
  
inputFile =
  inputFileWithSettings defaultEvaluateSettings
inputFileWithSettings
  :: EvaluateSettings
  -> Decoder a
  
  -> FilePath
  
  -> IO a
  
inputFileWithSettings settings ty path = do
  text <- Data.Text.IO.readFile path
  let inputSettings = InputSettings
        { _rootDirectory = takeDirectory path
        , _sourceName = path
        , _evaluateSettings = settings
        }
  inputWithSettings inputSettings ty text
inputExpr
    :: Text
    
    -> IO (Expr Src Void)
    
inputExpr =
  inputExprWithSettings defaultInputSettings
inputExprWithSettings
    :: InputSettings
    -> Text
    
    -> IO (Expr Src Void)
    
inputExprWithSettings settings txt = do
    expr  <- Dhall.Core.throws (Dhall.Parser.exprFromText (view sourceName settings) txt)
    let InputSettings {..} = settings
    let EvaluateSettings {..} = _evaluateSettings
    let transform =
               Lens.Family.set Dhall.Import.normalizer      _normalizer
            .  Lens.Family.set Dhall.Import.startingContext _startingContext
    let status = transform (Dhall.Import.emptyStatus _rootDirectory)
    expr' <- State.evalStateT (Dhall.Import.loadWith expr) status
    _ <- Dhall.Core.throws (Dhall.TypeCheck.typeWith (view startingContext settings) expr')
    pure (Dhall.Core.normalizeWith (view normalizer settings) expr')
rawInput
    :: Alternative f
    => Decoder a
    
    -> Expr s Void
    
    -> f a
    
rawInput (Decoder {..}) expr = do
    case extract (Dhall.Core.normalize expr) of
        Success x  -> pure x
        Failure _e -> empty
detailed :: IO a -> IO a
detailed =
    Control.Exception.handle handler1 . Control.Exception.handle handler0
  where
    handler0 :: Imported (TypeError Src Void) -> IO a
    handler0 (Imported ps e) =
        Control.Exception.throwIO (Imported ps (DetailedTypeError e))
    handler1 :: TypeError Src Void -> IO a
    handler1 e = Control.Exception.throwIO (DetailedTypeError e)
data Decoder a = Decoder
    { extract  :: Expr Src Void -> Extractor Src Void a
    
    , expected :: Expr Src Void
    
    }
    deriving (Functor)
bool :: Decoder Bool
bool = Decoder {..}
  where
    extract (BoolLit b) = pure b
    extract expr        = typeError expected expr
    expected = Bool
natural :: Decoder Natural
natural = Decoder {..}
  where
    extract (NaturalLit n) = pure n
    extract  expr             = typeError Natural expr
    expected = Natural
integer :: Decoder Integer
integer = Decoder {..}
  where
    extract (IntegerLit n) = pure n
    extract  expr          = typeError Integer expr
    expected = Integer
scientific :: Decoder Scientific
scientific = fmap Data.Scientific.fromFloatDigits double
double :: Decoder Double
double = Decoder {..}
  where
    extract (DoubleLit (DhallDouble n)) = pure n
    extract  expr                       = typeError Double expr
    expected = Double
lazyText :: Decoder Data.Text.Lazy.Text
lazyText = fmap Data.Text.Lazy.fromStrict strictText
strictText :: Decoder Text
strictText = Decoder {..}
  where
    extract (TextLit (Chunks [] t)) = pure t
    extract  expr = typeError Text expr
    expected = Text
maybe :: Decoder a -> Decoder (Maybe a)
maybe (Decoder extractIn expectedIn) = Decoder extractOut expectedOut
  where
    extractOut (Some e    ) = fmap Just (extractIn e)
    extractOut (App None _) = pure Nothing
    extractOut expr         = typeError expectedOut expr
    expectedOut = App Optional expectedIn
sequence :: Decoder a -> Decoder (Seq a)
sequence (Decoder extractIn expectedIn) = Decoder extractOut expectedOut
  where
    extractOut (ListLit _ es) = traverse extractIn es
    extractOut expr           = typeError expectedOut expr
    expectedOut = App List expectedIn
list :: Decoder a -> Decoder [a]
list = fmap Data.Foldable.toList . sequence
vector :: Decoder a -> Decoder (Vector a)
vector = fmap Data.Vector.fromList . list
function
    :: InterpretOptions
    -> Encoder a
    -> Decoder b
    -> Decoder (a -> b)
function options (Encoder {..}) (Decoder extractIn expectedIn) =
    Decoder extractOut expectedOut
  where
    normalizer_ = Just (inputNormalizer options)
    extractOut e = pure (\i -> case extractIn (Dhall.Core.normalizeWith normalizer_ (App e (embed i))) of
        Success o  -> o
        Failure _e -> error "FromDhall: You cannot decode a function if it does not have the correct type" )
    expectedOut = Pi "_" declared expectedIn
setIgnoringDuplicates :: (Ord a) => Decoder a -> Decoder (Data.Set.Set a)
setIgnoringDuplicates = fmap Data.Set.fromList . list
hashSetIgnoringDuplicates :: (Hashable a, Ord a)
                          => Decoder a
                          -> Decoder (Data.HashSet.HashSet a)
hashSetIgnoringDuplicates = fmap Data.HashSet.fromList . list
setFromDistinctList :: (Ord a, Show a) => Decoder a -> Decoder (Data.Set.Set a)
setFromDistinctList = setHelper Data.Set.size Data.Set.fromList
hashSetFromDistinctList :: (Hashable a, Ord a, Show a)
                        => Decoder a
                        -> Decoder (Data.HashSet.HashSet a)
hashSetFromDistinctList = setHelper Data.HashSet.size Data.HashSet.fromList
setHelper :: (Eq a, Foldable t, Show a)
          => (t a -> Int)
          -> ([a] -> t a)
          -> Decoder a
          -> Decoder (t a)
setHelper size toSet (Decoder extractIn expectedIn) = Decoder extractOut expectedOut
  where
    extractOut (ListLit _ es) = case traverse extractIn es of
        Success vSeq
            | sameSize               -> Success vSet
            | otherwise              -> extractError err
          where
            vList = Data.Foldable.toList vSeq
            vSet = toSet vList
            sameSize = size vSet == Data.Sequence.length vSeq
            duplicates = vList Data.List.\\ Data.Foldable.toList vSet
            err | length duplicates == 1 =
                     "One duplicate element in the list: "
                     <> (Data.Text.pack $ show $ head duplicates)
                | otherwise              = Data.Text.pack $ unwords
                     [ show $ length duplicates
                     , "duplicates were found in the list, including"
                     , show $ head duplicates
                     ]
        Failure f -> Failure f
    extractOut expr = typeError expectedOut expr
    expectedOut = App List expectedIn
map :: Ord k => Decoder k -> Decoder v -> Decoder (Map k v)
map k v = fmap Data.Map.fromList (list (pairFromMapEntry k v))
hashMap :: (Eq k, Hashable k) => Decoder k -> Decoder v -> Decoder (HashMap k v)
hashMap k v = fmap HashMap.fromList (list (pairFromMapEntry k v))
pairFromMapEntry :: Decoder k -> Decoder v -> Decoder (k, v)
pairFromMapEntry k v = Decoder extractOut expectedOut
  where
    extractOut (RecordLit kvs)
        | Just key <- Dhall.Map.lookup "mapKey" kvs
        , Just value <- Dhall.Map.lookup "mapValue" kvs
            = liftA2 (,) (extract k key) (extract v value)
    extractOut expr = typeError expectedOut expr
    expectedOut = Record (Dhall.Map.fromList [("mapKey", expected k), ("mapValue", expected v)])
unit :: Decoder ()
unit = Decoder extractOut expectedOut
  where
    extractOut (RecordLit fields)
        | Data.Foldable.null fields = pure ()
    extractOut expr = typeError (Record mempty) expr
    expectedOut = Record mempty
void :: Decoder Void
void = union mempty
string :: Decoder String
string = Data.Text.Lazy.unpack <$> lazyText
pair :: Decoder a -> Decoder b -> Decoder (a, b)
pair l r = Decoder extractOut expectedOut
  where
    extractOut expr@(RecordLit fields) =
      (,) <$> ( Data.Maybe.maybe (typeError expectedOut expr) (extract l) $ Dhall.Map.lookup "_1" fields)
          <*> ( Data.Maybe.maybe (typeError expectedOut expr) (extract r) $ Dhall.Map.lookup "_2" fields)
    extractOut expr = typeError expectedOut expr
    expectedOut =
        Record
            (Dhall.Map.fromList
                [ ("_1", expected l)
                , ("_2", expected r)
                ]
            )
class FromDhall a where
    autoWith:: InterpretOptions -> Decoder a
    default autoWith
        :: (Generic a, GenericFromDhall (Rep a)) => InterpretOptions -> Decoder a
    autoWith options = fmap GHC.Generics.to (evalState (genericAutoWith options) 1)
type Interpret = FromDhall
instance FromDhall Void where
    autoWith _ = void
instance FromDhall () where
    autoWith _ = unit
instance FromDhall Bool where
    autoWith _ = bool
instance FromDhall Natural where
    autoWith _ = natural
instance FromDhall Integer where
    autoWith _ = integer
instance FromDhall Scientific where
    autoWith _ = scientific
instance FromDhall Double where
    autoWith _ = double
instance {-# OVERLAPS #-} FromDhall [Char] where
    autoWith _ = string
instance FromDhall Data.Text.Lazy.Text where
    autoWith _ = lazyText
instance FromDhall Text where
    autoWith _ = strictText
instance FromDhall a => FromDhall (Maybe a) where
    autoWith opts = maybe (autoWith opts)
instance FromDhall a => FromDhall (Seq a) where
    autoWith opts = sequence (autoWith opts)
instance FromDhall a => FromDhall [a] where
    autoWith opts = list (autoWith opts)
instance FromDhall a => FromDhall (Vector a) where
    autoWith opts = vector (autoWith opts)
instance (FromDhall a, Ord a, Show a) => FromDhall (Data.Set.Set a) where
    autoWith opts = setFromDistinctList (autoWith opts)
instance (FromDhall a, Hashable a, Ord a, Show a) => FromDhall (Data.HashSet.HashSet a) where
    autoWith opts = hashSetFromDistinctList (autoWith opts)
instance (Ord k, FromDhall k, FromDhall v) => FromDhall (Map k v) where
    autoWith opts = Dhall.map (autoWith opts) (autoWith opts)
instance (Eq k, Hashable k, FromDhall k, FromDhall v) => FromDhall (HashMap k v) where
    autoWith opts = Dhall.hashMap (autoWith opts) (autoWith opts)
instance (ToDhall a, FromDhall b) => FromDhall (a -> b) where
    autoWith opts =
        function opts (injectWith opts) (autoWith opts)
instance (FromDhall a, FromDhall b) => FromDhall (a, b)
auto :: FromDhall a => Decoder a
auto = autoWith defaultInterpretOptions
newtype Result f = Result { _unResult :: f (Result f) }
resultToFix :: Functor f => Result f -> Fix f
resultToFix (Result x) = Fix (fmap resultToFix x)
instance FromDhall (f (Result f)) => FromDhall (Result f) where
    autoWith options = Decoder { expected = expected_, extract = extract_ }
      where
        expected_ = "result"
        extract_ (App _ expression) = do
            fmap Result (extract (autoWith options) expression)
        extract_ expression = do
            typeError expression expected_
instance (Functor f, FromDhall (f (Result f))) => FromDhall (Fix f) where
    autoWith options = Decoder { expected = expected_, extract = extract_ }
      where
        expected_ =
            Pi "result" (Const Dhall.Core.Type)
                (Pi "Make" (Pi "_" (expected (autoWith options :: Decoder (f (Result f)))) "result")
                    "result"
                )
        extract_ expression0 = go0 (Dhall.Core.alphaNormalize expression0)
          where
            go0 (Lam _ _ (Lam _ _  expression1)) =
                fmap resultToFix (extract (autoWith options) expression1)
            go0 _ = typeError expected_ expression0
genericAuto :: (Generic a, GenericFromDhall (Rep a)) => Decoder a
genericAuto = fmap to (evalState (genericAutoWith defaultInterpretOptions) 1)
data InterpretOptions = InterpretOptions
    { fieldModifier       :: Text -> Text
    
    
    , constructorModifier :: Text -> Text
    
    
    , singletonConstructors :: SingletonConstructors
    
    
    , inputNormalizer     :: Dhall.Core.ReifiedNormalizer Void
    
    
    
    }
data SingletonConstructors
    = Bare
    
    | Wrapped
    
    | Smart
    
defaultInterpretOptions :: InterpretOptions
defaultInterpretOptions = InterpretOptions
    { fieldModifier =
          id
    , constructorModifier =
          id
    , singletonConstructors =
          Smart
    , inputNormalizer =
          Dhall.Core.ReifiedNormalizer (const (pure Nothing))
    }
class GenericFromDhall f where
    genericAutoWith :: InterpretOptions -> State Int (Decoder (f a))
instance GenericFromDhall f => GenericFromDhall (M1 D d f) where
    genericAutoWith options = do
        res <- genericAutoWith options
        pure (fmap M1 res)
instance GenericFromDhall V1 where
    genericAutoWith _ = pure Decoder {..}
      where
        extract expr = typeError expected expr
        expected = Union mempty
unsafeExpectUnion
    :: Text -> Expr Src Void -> Dhall.Map.Map Text (Maybe (Expr Src Void))
unsafeExpectUnion _ (Union kts) =
    kts
unsafeExpectUnion name expression =
    Dhall.Core.internalError
        (name <> ": Unexpected constructor: " <> Dhall.Core.pretty expression)
unsafeExpectRecord
    :: Text -> Expr Src Void -> Dhall.Map.Map Text (Expr Src Void)
unsafeExpectRecord _ (Record kts) =
    kts
unsafeExpectRecord name expression =
    Dhall.Core.internalError
        (name <> ": Unexpected constructor: " <> Dhall.Core.pretty expression)
unsafeExpectUnionLit
    :: Text
    -> Expr Src Void
    -> (Text, Maybe (Expr Src Void))
unsafeExpectUnionLit _ (Field (Union _) k) =
    (k, Nothing)
unsafeExpectUnionLit _ (App (Field (Union _) k) v) =
    (k, Just v)
unsafeExpectUnionLit name expression =
    Dhall.Core.internalError
        (name <> ": Unexpected constructor: " <> Dhall.Core.pretty expression)
unsafeExpectRecordLit
    :: Text -> Expr Src Void -> Dhall.Map.Map Text (Expr Src Void)
unsafeExpectRecordLit _ (RecordLit kvs) =
    kvs
unsafeExpectRecordLit name expression =
    Dhall.Core.internalError
        (name <> ": Unexpected constructor: " <> Dhall.Core.pretty expression)
notEmptyRecordLit :: Expr s a -> Maybe (Expr s a)
notEmptyRecordLit e = case e of
    RecordLit m | null m -> Nothing
    _                    -> Just e
notEmptyRecord :: Expr s a -> Maybe (Expr s a)
notEmptyRecord e = case e of
    Record m | null m -> Nothing
    _                 -> Just e
extractUnionConstructor
    :: Expr s a -> Maybe (Text, Expr s a, Dhall.Map.Map Text (Maybe (Expr s a)))
extractUnionConstructor (App (Field (Union kts) fld) e) =
  return (fld, e, Dhall.Map.delete fld kts)
extractUnionConstructor (Field (Union kts) fld) =
  return (fld, RecordLit mempty, Dhall.Map.delete fld kts)
extractUnionConstructor _ =
  empty
instance (Constructor c1, Constructor c2, GenericFromDhall f1, GenericFromDhall f2) => GenericFromDhall (M1 C c1 f1 :+: M1 C c2 f2) where
    genericAutoWith options@(InterpretOptions {..}) = pure (Decoder {..})
      where
        nL :: M1 i c1 f1 a
        nL = undefined
        nR :: M1 i c2 f2 a
        nR = undefined
        nameL = constructorModifier (Data.Text.pack (conName nL))
        nameR = constructorModifier (Data.Text.pack (conName nR))
        extract e0 = do
          case extractUnionConstructor e0 of
            Just (name, e1, _) ->
              if
                | name == nameL -> fmap (L1 . M1) (extractL e1)
                | name == nameR -> fmap (R1 . M1) (extractR e1)
                | otherwise     -> typeError expected e0
            _ -> typeError expected e0
        expected =
            Union
                (Dhall.Map.fromList
                    [ (nameL, notEmptyRecord expectedL)
                    , (nameR, notEmptyRecord expectedR)
                    ]
                )
        Decoder extractL expectedL = evalState (genericAutoWith options) 1
        Decoder extractR expectedR = evalState (genericAutoWith options) 1
instance (Constructor c, GenericFromDhall (f :+: g), GenericFromDhall h) => GenericFromDhall ((f :+: g) :+: M1 C c h) where
    genericAutoWith options@(InterpretOptions {..}) = pure (Decoder {..})
      where
        n :: M1 i c h a
        n = undefined
        name = constructorModifier (Data.Text.pack (conName n))
        extract u = case extractUnionConstructor u of
          Just (name', e, _) ->
            if
              | name == name' -> fmap (R1 . M1) (extractR e)
              | otherwise     -> fmap  L1       (extractL u)
          Nothing -> typeError expected u
        expected =
            Union (Dhall.Map.insert name (notEmptyRecord expectedR) ktsL)
        Decoder extractL expectedL = evalState (genericAutoWith options) 1
        Decoder extractR expectedR = evalState (genericAutoWith options) 1
        ktsL = unsafeExpectUnion "genericAutoWith (:+:)" expectedL
instance (Constructor c, GenericFromDhall f, GenericFromDhall (g :+: h)) => GenericFromDhall (M1 C c f :+: (g :+: h)) where
    genericAutoWith options@(InterpretOptions {..}) = pure (Decoder {..})
      where
        n :: M1 i c f a
        n = undefined
        name = constructorModifier (Data.Text.pack (conName n))
        extract u = case extractUnionConstructor u of
          Just (name', e, _) ->
            if
              | name == name' -> fmap (L1 . M1) (extractL e)
              | otherwise     -> fmap  R1       (extractR u)
          _ -> typeError expected u
        expected =
            Union (Dhall.Map.insert name (notEmptyRecord expectedL) ktsR)
        Decoder extractL expectedL = evalState (genericAutoWith options) 1
        Decoder extractR expectedR = evalState (genericAutoWith options) 1
        ktsR = unsafeExpectUnion "genericAutoWith (:+:)" expectedR
instance (GenericFromDhall (f :+: g), GenericFromDhall (h :+: i)) => GenericFromDhall ((f :+: g) :+: (h :+: i)) where
    genericAutoWith options = pure (Decoder {..})
      where
        extract e = fmap L1 (extractL e) `ealt` fmap R1 (extractR e)
        expected = Union (Dhall.Map.union ktsL ktsR)
        Decoder extractL expectedL = evalState (genericAutoWith options) 1
        Decoder extractR expectedR = evalState (genericAutoWith options) 1
        ktsL = unsafeExpectUnion "genericAutoWith (:+:)" expectedL
        ktsR = unsafeExpectUnion "genericAutoWith (:+:)" expectedR
instance GenericFromDhall f => GenericFromDhall (M1 C c f) where
    genericAutoWith options = do
        res <- genericAutoWith options
        pure (fmap M1 res)
instance GenericFromDhall U1 where
    genericAutoWith _ = pure (Decoder {..})
      where
        extract _ = pure U1
        expected = Record (Dhall.Map.fromList [])
getSelName :: Selector s => M1 i s f a -> State Int Text
getSelName n = case selName n of
    "" -> do i <- get
             put (i + 1)
             pure (Data.Text.pack ("_" ++ show i))
    nn -> pure (Data.Text.pack nn)
instance (GenericFromDhall (f :*: g), GenericFromDhall (h :*: i)) => GenericFromDhall ((f :*: g) :*: (h :*: i)) where
    genericAutoWith options = do
        Decoder extractL expectedL <- genericAutoWith options
        Decoder extractR expectedR <- genericAutoWith options
        let ktsL = unsafeExpectRecord "genericAutoWith (:*:)" expectedL
        let ktsR = unsafeExpectRecord "genericAutoWith (:*:)" expectedR
        let expected = Record (Dhall.Map.union ktsL ktsR)
        let extract expression =
                liftA2 (:*:) (extractL expression) (extractR expression)
        return (Decoder {..})
instance (GenericFromDhall (f :*: g), Selector s, FromDhall a) => GenericFromDhall ((f :*: g) :*: M1 S s (K1 i a)) where
    genericAutoWith options@InterpretOptions{..} = do
        let nR :: M1 S s (K1 i a) r
            nR = undefined
        nameR <- fmap fieldModifier (getSelName nR)
        Decoder extractL expectedL <- genericAutoWith options
        let Decoder extractR expectedR = autoWith options
        let ktsL = unsafeExpectRecord "genericAutoWith (:*:)" expectedL
        let expected = Record (Dhall.Map.insert nameR expectedR ktsL)
        let extract expression = do
                let die = typeError expected expression
                case expression of
                    RecordLit kvs ->
                        case Dhall.Map.lookup nameR kvs of
                            Just expressionR ->
                                liftA2 (:*:)
                                    (extractL expression)
                                    (fmap (M1 . K1) (extractR expressionR))
                            _ -> die
                    _ -> die
        return (Decoder {..})
instance (Selector s, FromDhall a, GenericFromDhall (f :*: g)) => GenericFromDhall (M1 S s (K1 i a) :*: (f :*: g)) where
    genericAutoWith options@InterpretOptions{..} = do
        let nL :: M1 S s (K1 i a) r
            nL = undefined
        nameL <- fmap fieldModifier (getSelName nL)
        let Decoder extractL expectedL = autoWith options
        Decoder extractR expectedR <- genericAutoWith options
        let ktsR = unsafeExpectRecord "genericAutoWith (:*:)" expectedR
        let expected = Record (Dhall.Map.insert nameL expectedL ktsR)
        let extract expression = do
                let die = typeError expected expression
                case expression of
                    RecordLit kvs ->
                        case Dhall.Map.lookup nameL kvs of
                            Just expressionL ->
                                liftA2 (:*:)
                                    (fmap (M1 . K1) (extractL expressionL))
                                    (extractR expression)
                            _ -> die
                    _ -> die
        return (Decoder {..})
instance (Selector s1, Selector s2, FromDhall a1, FromDhall a2) => GenericFromDhall (M1 S s1 (K1 i1 a1) :*: M1 S s2 (K1 i2 a2)) where
    genericAutoWith options@InterpretOptions{..} = do
        let nL :: M1 S s1 (K1 i1 a1) r
            nL = undefined
        let nR :: M1 S s2 (K1 i2 a2) r
            nR = undefined
        nameL <- fmap fieldModifier (getSelName nL)
        nameR <- fmap fieldModifier (getSelName nR)
        let Decoder extractL expectedL = autoWith options
        let Decoder extractR expectedR = autoWith options
        let expected =
                Record
                    (Dhall.Map.fromList
                        [ (nameL, expectedL)
                        , (nameR, expectedR)
                        ]
                    )
        let extract expression = do
                let die = typeError expected expression
                case expression of
                    RecordLit kvs -> do
                        case liftA2 (,) (Dhall.Map.lookup nameL kvs) (Dhall.Map.lookup nameR kvs) of
                            Just (expressionL, expressionR) ->
                                liftA2 (:*:)
                                    (fmap (M1 . K1) (extractL expressionL))
                                    (fmap (M1 . K1) (extractR expressionR))
                            Nothing -> die
                    _ -> die
        return (Decoder {..})
instance (Selector s, FromDhall a) => GenericFromDhall (M1 S s (K1 i a)) where
    genericAutoWith options@InterpretOptions{..} = do
        let n :: M1 S s (K1 i a) r
            n = undefined
        name <- fmap fieldModifier (getSelName n)
        let Decoder { extract = extract', expected = expected'} = autoWith options
        let expected =
                case singletonConstructors of
                    Bare ->
                        expected'
                    Smart | selName n == "" ->
                        expected'
                    _ ->
                        Record (Dhall.Map.singleton name expected')
        let extract0 expression = fmap (M1 . K1) (extract' expression)
        let extract1 expression = do
                let die = typeError expected expression
                case expression of
                    RecordLit kvs -> do
                        case Dhall.Map.lookup name kvs of
                            Just subExpression ->
                                fmap (M1 . K1) (extract' subExpression)
                            Nothing ->
                                die
                    _ -> do
                        die
        let extract =
                case singletonConstructors of
                    Bare                    -> extract0
                    Smart | selName n == "" -> extract0
                    _                       -> extract1
        return (Decoder {..})
data Encoder a = Encoder
    { embed    :: a -> Expr Src Void
    
    , declared :: Expr Src Void
    
    }
instance Contravariant Encoder where
    contramap f (Encoder embed declared) = Encoder embed' declared
      where
        embed' x = embed (f x)
class ToDhall a where
    injectWith :: InterpretOptions -> Encoder a
    default injectWith
        :: (Generic a, GenericToDhall (Rep a)) => InterpretOptions -> Encoder a
    injectWith options
        = contramap GHC.Generics.from (evalState (genericToDhallWith options) 1)
type Inject = ToDhall
inject :: ToDhall a => Encoder a
inject = injectWith defaultInterpretOptions
genericToDhall
  :: (Generic a, GenericToDhall (Rep a)) => Encoder a
genericToDhall
    = contramap GHC.Generics.from (evalState (genericToDhallWith defaultInterpretOptions) 1)
instance ToDhall Void where
    injectWith _ = Encoder {..}
      where
        embed = Data.Void.absurd
        declared = Union mempty
instance ToDhall Bool where
    injectWith _ = Encoder {..}
      where
        embed = BoolLit
        declared = Bool
instance ToDhall Data.Text.Lazy.Text where
    injectWith _ = Encoder {..}
      where
        embed text =
            TextLit (Chunks [] (Data.Text.Lazy.toStrict text))
        declared = Text
instance ToDhall Text where
    injectWith _ = Encoder {..}
      where
        embed text = TextLit (Chunks [] text)
        declared = Text
instance {-# OVERLAPS #-} ToDhall String where
    injectWith options =
        contramap Data.Text.pack (injectWith options :: Encoder Text)
instance ToDhall Natural where
    injectWith _ = Encoder {..}
      where
        embed = NaturalLit
        declared = Natural
instance ToDhall Integer where
    injectWith _ = Encoder {..}
      where
        embed = IntegerLit
        declared = Integer
instance ToDhall Int where
    injectWith _ = Encoder {..}
      where
        embed = IntegerLit . toInteger
        declared = Integer
instance ToDhall Word where
    injectWith _ = Encoder {..}
      where
        embed = NaturalLit . fromIntegral
        declared = Natural
instance ToDhall Word8 where
    injectWith _ = Encoder {..}
      where
        embed = NaturalLit . fromIntegral
        declared = Natural
instance ToDhall Word16 where
    injectWith _ = Encoder {..}
      where
        embed = NaturalLit . fromIntegral
        declared = Natural
instance ToDhall Word32 where
    injectWith _ = Encoder {..}
      where
        embed = NaturalLit . fromIntegral
        declared = Natural
instance ToDhall Word64 where
    injectWith _ = Encoder {..}
      where
        embed = NaturalLit . fromIntegral
        declared = Natural
instance ToDhall Double where
    injectWith _ = Encoder {..}
      where
        embed = DoubleLit . DhallDouble
        declared = Double
instance ToDhall Scientific where
    injectWith options =
        contramap Data.Scientific.toRealFloat (injectWith options :: Encoder Double)
instance ToDhall () where
    injectWith _ = Encoder {..}
      where
        embed = const (RecordLit mempty)
        declared = Record mempty
instance ToDhall a => ToDhall (Maybe a) where
    injectWith options = Encoder embedOut declaredOut
      where
        embedOut (Just x ) = Some (embedIn x)
        embedOut  Nothing  = App None declaredIn
        Encoder embedIn declaredIn = injectWith options
        declaredOut = App Optional declaredIn
instance ToDhall a => ToDhall (Seq a) where
    injectWith options = Encoder embedOut declaredOut
      where
        embedOut xs = ListLit listType (fmap embedIn xs)
          where
            listType
                | null xs   = Just (App List declaredIn)
                | otherwise = Nothing
        declaredOut = App List declaredIn
        Encoder embedIn declaredIn = injectWith options
instance ToDhall a => ToDhall [a] where
    injectWith = fmap (contramap Data.Sequence.fromList) injectWith
instance ToDhall a => ToDhall (Vector a) where
    injectWith = fmap (contramap Data.Vector.toList) injectWith
instance ToDhall a => ToDhall (Data.Set.Set a) where
    injectWith = fmap (contramap Data.Set.toAscList) injectWith
instance ToDhall a => ToDhall (Data.HashSet.HashSet a) where
    injectWith = fmap (contramap Data.HashSet.toList) injectWith
instance (ToDhall a, ToDhall b) => ToDhall (a, b)
instance (ToDhall k, ToDhall v) => ToDhall (Data.Map.Map k v) where
    injectWith options = Encoder embedOut declaredOut
      where
        embedOut m = ListLit listType (mapEntries m)
          where
            listType
                | Data.Map.null m = Just declaredOut
                | otherwise       = Nothing
        declaredOut = App List (Record (Dhall.Map.fromList
                          [("mapKey", declaredK), ("mapValue", declaredV)]))
        mapEntries = Data.Sequence.fromList . fmap recordPair . Data.Map.toList
        recordPair (k, v) = RecordLit (Dhall.Map.fromList
                                [("mapKey", embedK k), ("mapValue", embedV v)])
        Encoder embedK declaredK = injectWith options
        Encoder embedV declaredV = injectWith options
instance (ToDhall k, ToDhall v) => ToDhall (HashMap k v) where
    injectWith options = Encoder embedOut declaredOut
      where
        embedOut m = ListLit listType (mapEntries m)
          where
            listType
                | HashMap.null m = Just declaredOut
                | otherwise       = Nothing
        declaredOut = App List (Record (Dhall.Map.fromList
                          [("mapKey", declaredK), ("mapValue", declaredV)]))
        mapEntries = Data.Sequence.fromList . fmap recordPair . HashMap.toList
        recordPair (k, v) = RecordLit (Dhall.Map.fromList
                                [("mapKey", embedK k), ("mapValue", embedV v)])
        Encoder embedK declaredK = injectWith options
        Encoder embedV declaredV = injectWith options
class GenericToDhall f where
    genericToDhallWith :: InterpretOptions -> State Int (Encoder (f a))
instance GenericToDhall f => GenericToDhall (M1 D d f) where
    genericToDhallWith options = do
        res <- genericToDhallWith options
        pure (contramap unM1 res)
instance GenericToDhall f => GenericToDhall (M1 C c f) where
    genericToDhallWith options = do
        res <- genericToDhallWith options
        pure (contramap unM1 res)
instance (Selector s, ToDhall a) => GenericToDhall (M1 S s (K1 i a)) where
    genericToDhallWith options@InterpretOptions{..} = do
        let Encoder { embed = embed', declared = declared' } =
                injectWith options
        let n :: M1 S s (K1 i a) r
            n = undefined
        name <- fieldModifier <$> getSelName n
        let embed0 (M1 (K1 x)) = embed' x
        let embed1 (M1 (K1 x)) =
                RecordLit (Dhall.Map.singleton name (embed' x))
        let embed =
                case singletonConstructors of
                    Bare                    -> embed0
                    Smart | selName n == "" -> embed0
                    _                       -> embed1
        let declared =
                case singletonConstructors of
                    Bare ->
                        declared'
                    Smart | selName n == "" ->
                        declared'
                    _ ->
                        Record (Dhall.Map.singleton name declared')
        return (Encoder {..})
instance (Constructor c1, Constructor c2, GenericToDhall f1, GenericToDhall f2) => GenericToDhall (M1 C c1 f1 :+: M1 C c2 f2) where
    genericToDhallWith options@(InterpretOptions {..}) = pure (Encoder {..})
      where
        embed (L1 (M1 l)) =
            case notEmptyRecordLit (embedL l) of
                Nothing ->
                    Field declared keyL
                Just valL ->
                    App (Field declared keyL) valL
        embed (R1 (M1 r)) =
            case notEmptyRecordLit (embedR r) of
                Nothing ->
                    Field declared keyR
                Just valR ->
                    App (Field declared keyR) valR
        declared =
            Union
                (Dhall.Map.fromList
                    [ (keyL, notEmptyRecord declaredL)
                    , (keyR, notEmptyRecord declaredR)
                    ]
                )
        nL :: M1 i c1 f1 a
        nL = undefined
        nR :: M1 i c2 f2 a
        nR = undefined
        keyL = constructorModifier (Data.Text.pack (conName nL))
        keyR = constructorModifier (Data.Text.pack (conName nR))
        Encoder embedL declaredL = evalState (genericToDhallWith options) 1
        Encoder embedR declaredR = evalState (genericToDhallWith options) 1
instance (Constructor c, GenericToDhall (f :+: g), GenericToDhall h) => GenericToDhall ((f :+: g) :+: M1 C c h) where
    genericToDhallWith options@(InterpretOptions {..}) = pure (Encoder {..})
      where
        embed (L1 l) =
            case maybeValL of
                Nothing   -> Field declared keyL
                Just valL -> App (Field declared keyL) valL
          where
            (keyL, maybeValL) =
              unsafeExpectUnionLit "genericToDhallWith (:+:)" (embedL l)
        embed (R1 (M1 r)) =
            case notEmptyRecordLit (embedR r) of
                Nothing   -> Field declared keyR
                Just valR -> App (Field declared keyR) valR
        nR :: M1 i c h a
        nR = undefined
        keyR = constructorModifier (Data.Text.pack (conName nR))
        declared = Union (Dhall.Map.insert keyR (notEmptyRecord declaredR) ktsL)
        Encoder embedL declaredL = evalState (genericToDhallWith options) 1
        Encoder embedR declaredR = evalState (genericToDhallWith options) 1
        ktsL = unsafeExpectUnion "genericToDhallWith (:+:)" declaredL
instance (Constructor c, GenericToDhall f, GenericToDhall (g :+: h)) => GenericToDhall (M1 C c f :+: (g :+: h)) where
    genericToDhallWith options@(InterpretOptions {..}) = pure (Encoder {..})
      where
        embed (L1 (M1 l)) =
            case notEmptyRecordLit (embedL l) of
                Nothing   -> Field declared keyL
                Just valL -> App (Field declared keyL) valL
        embed (R1 r) =
            case maybeValR of
                Nothing   -> Field declared keyR
                Just valR -> App (Field declared keyR) valR
          where
            (keyR, maybeValR) =
                unsafeExpectUnionLit "genericToDhallWith (:+:)" (embedR r)
        nL :: M1 i c f a
        nL = undefined
        keyL = constructorModifier (Data.Text.pack (conName nL))
        declared = Union (Dhall.Map.insert keyL (notEmptyRecord declaredL) ktsR)
        Encoder embedL declaredL = evalState (genericToDhallWith options) 1
        Encoder embedR declaredR = evalState (genericToDhallWith options) 1
        ktsR = unsafeExpectUnion "genericToDhallWith (:+:)" declaredR
instance (GenericToDhall (f :+: g), GenericToDhall (h :+: i)) => GenericToDhall ((f :+: g) :+: (h :+: i)) where
    genericToDhallWith options = pure (Encoder {..})
      where
        embed (L1 l) =
            case maybeValL of
                Nothing   -> Field declared keyL
                Just valL -> App (Field declared keyL) valL
          where
            (keyL, maybeValL) =
                unsafeExpectUnionLit "genericToDhallWith (:+:)" (embedL l)
        embed (R1 r) =
            case maybeValR of
                Nothing   -> Field declared keyR
                Just valR -> App (Field declared keyR) valR
          where
            (keyR, maybeValR) =
                unsafeExpectUnionLit "genericToDhallWith (:+:)" (embedR r)
        declared = Union (Dhall.Map.union ktsL ktsR)
        Encoder embedL declaredL = evalState (genericToDhallWith options) 1
        Encoder embedR declaredR = evalState (genericToDhallWith options) 1
        ktsL = unsafeExpectUnion "genericToDhallWith (:+:)" declaredL
        ktsR = unsafeExpectUnion "genericToDhallWith (:+:)" declaredR
instance (GenericToDhall (f :*: g), GenericToDhall (h :*: i)) => GenericToDhall ((f :*: g) :*: (h :*: i)) where
    genericToDhallWith options = do
        Encoder embedL declaredL <- genericToDhallWith options
        Encoder embedR declaredR <- genericToDhallWith options
        let embed (l :*: r) =
                RecordLit (Dhall.Map.union mapL mapR)
              where
                mapL =
                    unsafeExpectRecordLit "genericToDhallWith (:*:)" (embedL l)
                mapR =
                    unsafeExpectRecordLit "genericToDhallWith (:*:)" (embedR r)
        let declared = Record (Dhall.Map.union mapL mapR)
              where
                mapL = unsafeExpectRecord "genericToDhallWith (:*:)" declaredL
                mapR = unsafeExpectRecord "genericToDhallWith (:*:)" declaredR
        pure (Encoder {..})
instance (GenericToDhall (f :*: g), Selector s, ToDhall a) => GenericToDhall ((f :*: g) :*: M1 S s (K1 i a)) where
    genericToDhallWith options@InterpretOptions{..} = do
        let nR :: M1 S s (K1 i a) r
            nR = undefined
        nameR <- fmap fieldModifier (getSelName nR)
        Encoder embedL declaredL <- genericToDhallWith options
        let Encoder embedR declaredR = injectWith options
        let embed (l :*: M1 (K1 r)) =
                RecordLit (Dhall.Map.insert nameR (embedR r) mapL)
              where
                mapL =
                    unsafeExpectRecordLit "genericToDhallWith (:*:)" (embedL l)
        let declared = Record (Dhall.Map.insert nameR declaredR mapL)
              where
                mapL = unsafeExpectRecord "genericToDhallWith (:*:)" declaredL
        return (Encoder {..})
instance (Selector s, ToDhall a, GenericToDhall (f :*: g)) => GenericToDhall (M1 S s (K1 i a) :*: (f :*: g)) where
    genericToDhallWith options@InterpretOptions{..} = do
        let nL :: M1 S s (K1 i a) r
            nL = undefined
        nameL <- fmap fieldModifier (getSelName nL)
        let Encoder embedL declaredL = injectWith options
        Encoder embedR declaredR <- genericToDhallWith options
        let embed (M1 (K1 l) :*: r) =
                RecordLit (Dhall.Map.insert nameL (embedL l) mapR)
              where
                mapR =
                    unsafeExpectRecordLit "genericToDhallWith (:*:)" (embedR r)
        let declared = Record (Dhall.Map.insert nameL declaredL mapR)
              where
                mapR = unsafeExpectRecord "genericToDhallWith (:*:)" declaredR
        return (Encoder {..})
instance (Selector s1, Selector s2, ToDhall a1, ToDhall a2) => GenericToDhall (M1 S s1 (K1 i1 a1) :*: M1 S s2 (K1 i2 a2)) where
    genericToDhallWith options@InterpretOptions{..} = do
        let nL :: M1 S s1 (K1 i1 a1) r
            nL = undefined
        let nR :: M1 S s2 (K1 i2 a2) r
            nR = undefined
        nameL <- fmap fieldModifier (getSelName nL)
        nameR <- fmap fieldModifier (getSelName nR)
        let Encoder embedL declaredL = injectWith options
        let Encoder embedR declaredR = injectWith options
        let embed (M1 (K1 l) :*: M1 (K1 r)) =
                RecordLit
                    (Dhall.Map.fromList
                        [ (nameL, embedL l), (nameR, embedR r) ]
                    )
        let declared =
                Record
                    (Dhall.Map.fromList
                        [ (nameL, declaredL), (nameR, declaredR) ]
                    )
        return (Encoder {..})
instance GenericToDhall U1 where
    genericToDhallWith _ = pure (Encoder {..})
      where
        embed _ = RecordLit mempty
        declared = Record mempty
newtype RecordDecoder a =
  RecordDecoder
    ( Data.Functor.Product.Product
        ( Control.Applicative.Const
            ( Dhall.Map.Map
                Text
                ( Expr Src Void )
            )
        )
        ( Data.Functor.Compose.Compose
            ( (->) ( Expr Src Void ) )
            (Extractor Src Void)
        )
        a
    )
  deriving (Functor, Applicative)
record :: RecordDecoder a -> Dhall.Decoder a
record ( RecordDecoder ( Data.Functor.Product.Pair ( Control.Applicative.Const fields ) ( Data.Functor.Compose.Compose extractF ) ) ) =
  Decoder
    { extract =
        extractF
    , expected =
        Record fields
    }
field :: Text -> Decoder a -> RecordDecoder a
field key valueDecoder@(Decoder extract expected) =
  let
    extractBody expr@(RecordLit fields) = case Dhall.Map.lookup key fields of
      Just v -> extract v
      _ -> typeError expected expr
    extractBody expr = typeError expected expr
  in
    RecordDecoder
      ( Data.Functor.Product.Pair
          ( Control.Applicative.Const
              ( Dhall.Map.singleton
                  key
                  ( Dhall.expected valueDecoder )
              )
          )
          ( Data.Functor.Compose.Compose extractBody )
      )
newtype UnionDecoder a =
    UnionDecoder
      ( Data.Functor.Compose.Compose (Dhall.Map.Map Text) Decoder a )
  deriving (Functor)
instance Data.Semigroup.Semigroup (UnionDecoder a) where
    (<>) = coerce ((<>) :: Dhall.Map.Map Text (Decoder a) -> Dhall.Map.Map Text (Decoder a) -> Dhall.Map.Map Text (Decoder a))
instance Monoid (UnionDecoder a) where
    mempty = coerce (mempty :: Dhall.Map.Map Text (Decoder a))
    mappend = (Data.Semigroup.<>)
union :: UnionDecoder a -> Decoder a
union (UnionDecoder (Data.Functor.Compose.Compose mp)) = Decoder
    { extract  = extractF
    , expected = Union expect
    }
  where
    expect = (notEmptyRecord . Dhall.expected) <$> mp
    extractF e0 =
      let result = do
            (fld, e1, rest) <- extractUnionConstructor e0
            t <- Dhall.Map.lookup fld mp
            guard $ Dhall.Core.Union rest `Dhall.Core.judgmentallyEqual`
                      Dhall.Core.Union (Dhall.Map.delete fld expect)
            pure (t, e1)
      in Data.Maybe.maybe (typeError (Union expect) e0) (uncurry extract) result
constructor :: Text -> Decoder a -> UnionDecoder a
constructor key valueDecoder = UnionDecoder
    ( Data.Functor.Compose.Compose (Dhall.Map.singleton key valueDecoder) )
(>*<) :: Divisible f => f a -> f b -> f (a, b)
(>*<) = divided
infixr 5 >*<
newtype RecordEncoder a
  = RecordEncoder (Dhall.Map.Map Text (Encoder a))
instance Contravariant RecordEncoder where
  contramap f (RecordEncoder encodeTypeRecord) = RecordEncoder $ contramap f <$> encodeTypeRecord
instance Divisible RecordEncoder where
  divide f (RecordEncoder bEncoderRecord) (RecordEncoder cEncoderRecord) =
      RecordEncoder
    $ Dhall.Map.union
      ((contramap $ fst . f) <$> bEncoderRecord)
      ((contramap $ snd . f) <$> cEncoderRecord)
  conquer = RecordEncoder mempty
encodeFieldWith :: Text -> Encoder a -> RecordEncoder a
encodeFieldWith name encodeType = RecordEncoder $ Dhall.Map.singleton name encodeType
encodeField :: ToDhall a => Text -> RecordEncoder a
encodeField name = encodeFieldWith name inject
recordEncoder :: RecordEncoder a -> Encoder a
recordEncoder (RecordEncoder encodeTypeRecord) = Encoder makeRecordLit recordType
  where
    recordType = Record $ declared <$> encodeTypeRecord
    makeRecordLit x = RecordLit $ (($ x) . embed) <$> encodeTypeRecord
newtype UnionEncoder a =
  UnionEncoder
    ( Data.Functor.Product.Product
        ( Control.Applicative.Const
            ( Dhall.Map.Map
                Text
                ( Expr Src Void )
            )
        )
        ( Op (Text, Expr Src Void) )
        a
    )
  deriving (Contravariant)
(>|<) :: UnionEncoder a -> UnionEncoder b -> UnionEncoder (Either a b)
UnionEncoder (Data.Functor.Product.Pair (Control.Applicative.Const mx) (Op fx))
    >|< UnionEncoder (Data.Functor.Product.Pair (Control.Applicative.Const my) (Op fy)) =
    UnionEncoder
      ( Data.Functor.Product.Pair
          ( Control.Applicative.Const (mx <> my) )
          ( Op (either fx fy) )
      )
infixr 5 >|<
unionEncoder :: UnionEncoder a -> Encoder a
unionEncoder ( UnionEncoder ( Data.Functor.Product.Pair ( Control.Applicative.Const fields ) ( Op embedF ) ) ) =
    Encoder
      { embed = \x ->
          let (name, y) = embedF x
          in  case notEmptyRecordLit y of
                  Nothing  -> Field (Union fields') name
                  Just val -> App (Field (Union fields') name) val
      , declared =
          Union fields'
      }
  where
    fields' = fmap notEmptyRecord fields
encodeConstructorWith
    :: Text
    -> Encoder a
    -> UnionEncoder a
encodeConstructorWith name encodeType = UnionEncoder $
    Data.Functor.Product.Pair
      ( Control.Applicative.Const
          ( Dhall.Map.singleton
              name
              ( declared encodeType )
          )
      )
      ( Op ( (name,) . embed encodeType )
      )
encodeConstructor
    :: ToDhall a
    => Text
    -> UnionEncoder a
encodeConstructor name = encodeConstructorWith name inject