-- | Helper functions for enforcing strictness.
module Data.Unit.Strict (
  StrictUnit (),
  forceElemsToWHNF,
)
where

-- | Force all of the elements of a 'Foldable' to weak head normal form.
--
-- In order to ensure that all of the elements of a 'Foldable' are strict, we
-- can simply 'foldMap' over it and 'seq' each value with '()'. However,
-- '()''s 'mappend' implementation is actually completely lazy: @_ <> _ = ()@
-- So, in order to work around this, we instead utilize this newly defined
-- 'StrictUnit' whose 'mappend' implementation is specifically strict.
forceElemsToWHNF :: Foldable t => t a -> t a
forceElemsToWHNF :: forall (t :: * -> *) a. Foldable t => t a -> t a
forceElemsToWHNF t a
x = forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap (seq :: forall a b. a -> b -> b
`seq` StrictUnit
StrictUnit) t a
x seq :: forall a b. a -> b -> b
`seq` t a
x

-- | The equivalent of '()', but with a strict 'mappend' implementation.
--
-- For more information, see the documentation for 'forceElemsToWHNF'.
data StrictUnit = StrictUnit

instance Semigroup StrictUnit where
  StrictUnit
StrictUnit <> :: StrictUnit -> StrictUnit -> StrictUnit
<> StrictUnit
StrictUnit = StrictUnit
StrictUnit

instance Monoid StrictUnit where
  mempty :: StrictUnit
mempty = StrictUnit
StrictUnit