{-# LANGUAGE DerivingVia #-} {-# LANGUAGE EmptyCase #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE LinearTypes #-} {-# LANGUAGE PartialTypeSignatures #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE Trustworthy #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE NoImplicitPrelude #-} {-# OPTIONS_GHC -Wno-partial-type-signatures #-} {-# OPTIONS_HADDOCK hide #-} module Data.Unrestricted.Linear.Internal.Consumable ( -- * Consumable Consumable (..), lseq, seqUnit, -- * Generic deriving GConsumable, genericConsume, ) where import Data.List.NonEmpty (NonEmpty) import qualified Data.Monoid as Monoid import qualified Data.Replicator.Linear.Internal as Replicator import qualified Data.Replicator.Linear.Internal.ReplicationStream as ReplicationStream import qualified Data.Semigroup as Semigroup import Data.Unrestricted.Linear.Internal.Ur import qualified Data.Vector as Vector import Data.Void (Void) import GHC.Tuple (Solo) import GHC.Types (Multiplicity (..)) import Generics.Linear import Prelude.Linear.Generically import Prelude.Linear.Internal import qualified Unsafe.Linear as Unsafe import qualified Prelude as Prelude class Consumable a where consume :: a %1 -> () -- | Consume the unit and return the second argument. -- This is like 'seq' but since the first argument is restricted to be of type -- @()@ it is consumed, hence @seqUnit@ is linear in its first argument. seqUnit :: () %1 -> b %1 -> b seqUnit () b = b -- | Consume the first argument and return the second argument. -- This is like 'seq' but the first argument is restricted to be 'Consumable'. lseq :: Consumable a => a %1 -> b %1 -> b lseq a b = seqUnit (consume a) b infixr 0 `lseq` -- same fixity as base.seq -- ---------------- -- Instances instance Consumable (ReplicationStream.ReplicationStream a) where consume = ReplicationStream.consume instance Consumable (Replicator.Replicator a) where consume = Replicator.consume instance Consumable a => Consumable (Vector.Vector a) where consume xs = consume (Unsafe.toLinear Vector.toList xs) -- Prelude and primitive instances deriving via Generically Prelude.Char instance Consumable Prelude.Char deriving via Generically Prelude.Double instance Consumable Prelude.Double deriving via Generically Prelude.Float instance Consumable Prelude.Float deriving via Generically Prelude.Int instance Consumable Prelude.Int deriving via Generically Prelude.Word instance Consumable Prelude.Word deriving via Generically Prelude.Ordering instance Consumable Prelude.Ordering deriving via Generically Prelude.Bool instance Consumable Prelude.Bool deriving via Generically () instance Consumable () instance Consumable Void where consume = \case {} deriving via Generically (Solo a) instance _ => Consumable (Solo a) deriving via Generically (a, b) instance _ => Consumable (a, b) deriving via Generically (a, b, c) instance _ => Consumable (a, b, c) deriving via Generically (a, b, c, d) instance _ => Consumable (a, b, c, d) deriving via Generically (a, b, c, d, e) instance _ => Consumable (a, b, c, d, e) deriving via Generically (Prelude.Maybe a) instance _ => Consumable (Prelude.Maybe a) deriving via Generically (Prelude.Either e a) instance _ => Consumable (Prelude.Either e a) deriving via Generically [a] instance _ => Consumable [a] deriving via Generically (NonEmpty a) instance _ => Consumable (NonEmpty a) deriving via Generically (Ur a) instance Consumable (Ur a) -- Data.Semigroup instances deriving via Generically (Semigroup.Arg a b) instance _ => Consumable (Semigroup.Arg a b) deriving newtype instance _ => Consumable (Semigroup.Min a) deriving newtype instance _ => Consumable (Semigroup.Max a) deriving newtype instance _ => Consumable (Semigroup.First a) deriving newtype instance _ => Consumable (Semigroup.Last a) deriving newtype instance _ => Consumable (Semigroup.WrappedMonoid a) deriving newtype instance _ => Consumable (Semigroup.Dual a) deriving newtype instance Consumable Semigroup.All deriving newtype instance Consumable Semigroup.Any deriving newtype instance _ => Consumable (Semigroup.Sum a) deriving newtype instance _ => Consumable (Semigroup.Product a) -- Data.Monoid instances deriving newtype instance _ => Consumable (Monoid.First a) deriving newtype instance _ => Consumable (Monoid.Last a) deriving newtype instance _ => Consumable (Monoid.Alt f a) deriving newtype instance _ => Consumable (Monoid.Ap f a) -- ---------------- -- Generic deriving instance (Generic a, GConsumable (Rep a)) => Consumable (Generically a) where consume (Generically x) = genericConsume x genericConsume :: (Generic a, GConsumable (Rep a)) => a %1 -> () genericConsume = gconsume . from {-# INLINEABLE genericConsume #-} -- | A class for generic representations that can be consumed. class GConsumable f where gconsume :: f p %1 -> () instance GConsumable V1 where gconsume = \case {} {-# INLINE gconsume #-} instance GConsumable U1 where gconsume U1 = () {-# INLINE gconsume #-} instance (GConsumable f, GConsumable g) => GConsumable (f :+: g) where gconsume (L1 a) = gconsume a gconsume (R1 a) = gconsume a {-# INLINE gconsume #-} instance (GConsumable f, GConsumable g) => GConsumable (f :*: g) where gconsume (a :*: b) = gconsume a `seqUnit` gconsume b {-# INLINE gconsume #-} instance Consumable c => GConsumable (K1 i c) where gconsume (K1 c) = consume c {-# INLINE gconsume #-} instance GConsumable f => GConsumable (M1 i t f) where gconsume (M1 a) = gconsume a {-# INLINE gconsume #-} -- This split is a bit awkward. We'd like to be able to *default* -- the multiplicity to `Many` when it's polymorphic. We'll be able -- to do that once the Exportable Named Defaults Proposal -- (https://github.com/ghc-proposals/ghc-proposals/pull/409#issuecomment-931839874) -- has been implemented. The same goes for Dupable and Movable. instance GConsumable (MP1 'Many f) where gconsume (MP1 _) = () {-# INLINE gconsume #-} instance GConsumable f => GConsumable (MP1 'One f) where gconsume (MP1 x) = gconsume x {-# INLINE gconsume #-} -- Instances for unlifted generic representations -- -- /!\ 'Char#', 'Double#', 'Float#', 'Int#', 'Word#' are unboxed data-types, -- and therefore they cannot have any linear values hidden in a closure -- anywhere. Therefore it is safe to call non-linear functions linearly on -- these types. We refrain from including a 'GConsumable' instance for 'UAddr' -- for the moment, as that seems potentially confusing—pointers usually -- must be created, duplicated, and destroyed rather carefully. /!\ instance GConsumable UChar where gconsume (UChar x) = Unsafe.toLinear (\_ -> ()) x instance GConsumable UDouble where gconsume (UDouble x) = Unsafe.toLinear (\_ -> ()) x instance GConsumable UFloat where gconsume (UFloat x) = Unsafe.toLinear (\_ -> ()) x instance GConsumable UInt where gconsume (UInt x) = Unsafe.toLinear (\_ -> ()) x instance GConsumable UWord where gconsume (UWord x) = Unsafe.toLinear (\_ -> ()) x