{-# LANGUAGE MagicHash #-}
{-# LANGUAGE NoImplicitPrelude #-}

-- | This module defines a stream-like type named 'Replicator', which is
-- mainly used in the definition of the 'Data.Unrestricted.Dupable' class
-- to provide efficient linear duplication.
-- The API of 'Replicator' is close to the one of an infinite stream: it
-- can either produce a new value linearly (with 'next' or 'next#'), or be
-- linearly discarded (with 'consume' or 'extract').
--
-- A crucial aspect, from a performance standpoint, is that the 'pure' function
-- (which takes an unrestricted argument) is implemented efficiently: the
-- 'Replicator' returns /the same/ value on each call to 'next'. That is, the
-- pointer is always shared. This will allow 'Data.Unrestricted.Movable' types
-- to be given an efficient instance of 'Data.Unrestricted.Dupable'. Instances
-- of both 'Data.Unrestricted.Movable' and 'Data.Unrestricted.Dupable' typically
-- involve deep copies. The implementation of 'pure' lets us make sure that, for
-- @Movable@ types, only one deep copy is performed, rather than one per
-- additional replica.
--
-- Strictly speaking, the implementation of '(<*>)' plays a role in all this as
-- well:
-- For two 'pure' 'Replicators' @fs@ and @as@, @fs \<*\> as@  is a pure
-- 'Replicator'. Together, 'pure' and '(<*>)' form the
-- 'Data.Functor.Linear.Applicative' instance of 'Replicator'.
module Data.Replicator.Linear
  ( Replicator,
    consume,
    duplicate,
    map,
    pure,
    (<*>),
    next,
    next#,
    take,
    extract,
    extend,
    Elim,
    elim,
  )
where

import Data.Replicator.Linear.Internal
import Data.Replicator.Linear.Internal.Instances ()