-- | Create generators for user-defined types, provided via the environment.
-- Generators for built-in types must be given from outside.
createDataGen :: (MonadRandom m, Ord c, Ord tc, Ord tv)
  => TcEnv v c tc tv
  -> Map tc (DataGen c tv (Sized m)) -- ^ Built-in generators
  -> Map tc (DataGen c tv m) -- ^ Base case generators
  -> (Map tc [(Int, DataPat c tc tv)], Map tc [(Int, DataPat c tc tv)]) -- ^ Inlinings
  -> Map tc (DataGen c tv (Sized m))
createDataGen env g baseGen (inlined, inlinedBase) = fix $ \g' ->
  Map.union g
    $ Map.mapWithKey (mkGen g') (baseGen `mapZip` (tyConEnv env `mapZip'` inlined))
  where
    mkGen g' tc (baseGen, (vs, alts)) =
      let alts' = map (\(w, a) -> (w, (countLeaves a, a))) alts
      in mkDataGen g' tc baseGen vs alts'

-- | Base generators.
createDataGen :: (MonadRandom m, Ord c, Ord tc, Ord tv)
  => TcEnv v c tc tv
  -> Map tc (DataGen c tv (Sized m)) -- ^ Built-in generators
  -> Map tc (DataGen c tv m) -- ^ Base case generators
  -> (Map tc [(Int, DataPat c tc tv)], Map tc [(Int, DataPat c tc tv)]) -- ^ Inlinings
  -> Map tc (DataGen c tv (Sized m))
createDataGen env g baseGen (inlined, inlinedBase) = fix $ \g' ->
  Map.union g
    $ Map.mapWithKey (mkGen g') (baseGen `mapZip` (tyConEnv env `mapZip'` inlined))
  where
    mkGen g' tc (baseGen, (vs, alts)) =
      let alts' = map (\(w, a) -> (w, (countLeaves a, a))) alts
      in mkDataGen g' tc baseGen vs alts'

-- | Base generators.
createDataGen env g baseGen (inlined, inlinedBase) = fix $ \g' ->
  Map.union g
    $ Map.mapWithKey (mkGen g') (baseGen `mapZip` (tyConEnv env `mapZip'` inlined))
  where
    mkGen g' tc (baseGen, (vs, alts)) =
      let alts' = map (\(w, a) -> (w, (countLeaves a, a))) alts
      in mkDataGen g' tc baseGen vs alts'

-- | Base generators.