{-# LANGUAGE DataKinds #-} {-# LANGUAGE DerivingVia #-} {-# LANGUAGE EmptyCase #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE LinearTypes #-} {-# LANGUAGE QuantifiedConstraints #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE Trustworthy #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE NoImplicitPrelude #-} {-# OPTIONS_HADDOCK hide #-} module Data.Unrestricted.Linear.Internal.Movable ( -- * Movable Movable (..), GMovable, genericMove, ) where import qualified Data.Functor.Linear.Internal.Applicative as Data import qualified Data.Functor.Linear.Internal.Functor as Data import Data.List.NonEmpty (NonEmpty (..)) import qualified Data.Semigroup as Semigroup import Data.Unrestricted.Linear.Internal.Dupable import Data.Unrestricted.Linear.Internal.Ur 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 Prelude (Bool (..), Char, Double, Float, Int, Ordering (..), Word) import qualified Prelude as Prelude -- | Use @'Movable' a@ to represent a type which can be used many times even -- when given linearly. Simple data types such as 'Bool' or @[]@ are 'Movable'. -- Though, bear in mind that this typically induces a deep copy of the value. -- -- Formally, @'Movable' a@ is the class of -- [coalgebras](https://ncatlab.org/nlab/show/coalgebra+over+a+comonad) of the -- 'Ur' comonad. That is -- -- * @unur (move x) = x@ -- * @move \@(Ur a) (move \@a x) = fmap (move \@a) $ move \@a x@ -- -- Additionally, a 'Movable' instance must be compatible with its 'Dupable' parent instance. That is: -- -- * @case move x of {Ur _ -> ()} = consume x@ -- * @case move x of {Ur x -> (x, x)} = dup2 x@ class Dupable a => Movable a where move :: a %1 -> Ur a -- ------------- -- Instances deriving via Generically Bool instance Movable Bool deriving via Generically Char instance Movable Char deriving via Generically Double instance Movable Double deriving via Generically Float instance Movable Float deriving via Generically Int instance Movable Int deriving via Generically Word instance Movable Word deriving via Generically Prelude.Ordering instance Movable Prelude.Ordering instance Movable () where move () = Ur () deriving via Generically (Solo a) instance Movable a => Movable (Solo a) deriving via Generically (a, b) instance (Movable a, Movable b) => Movable (a, b) deriving via Generically (a, b, c) instance (Movable a, Movable b, Movable c) => Movable (a, b, c) deriving via Generically (a, b, c, d) instance (Movable a, Movable b, Movable c, Movable d) => Movable (a, b, c, d) deriving via Generically (a, b, c, d, e) instance (Movable a, Movable b, Movable c, Movable d, Movable e) => Movable (a, b, c, d, e) instance Movable a => Movable (Prelude.Maybe a) where move (Prelude.Nothing) = Ur Prelude.Nothing move (Prelude.Just x) = Data.fmap Prelude.Just (move x) instance (Movable a, Movable b) => Movable (Prelude.Either a b) where move (Prelude.Left a) = Data.fmap Prelude.Left (move a) move (Prelude.Right b) = Data.fmap Prelude.Right (move b) instance Movable a => Movable [a] where -- The explicit go function lets this specialize. move = go where go :: [a] %1 -> Ur [a] go [] = Ur [] go (a : l) = (:) Data.<$> move a Data.<*> go l instance Movable a => Movable (NonEmpty a) where move (x :| xs) = (:|) Data.<$> move x Data.<*> move xs instance Movable (Ur a) where move (Ur a) = Ur (Ur a) -- Some stock instances deriving newtype instance Movable a => Movable (Semigroup.Sum a) deriving newtype instance Movable a => Movable (Semigroup.Product a) deriving newtype instance Movable Semigroup.All deriving newtype instance Movable Semigroup.Any -- ------------- -- Generic deriving instance (Generic a, GMovable (Rep a)) => Movable (Generically a) where move = Data.fmap (Generically . to) . gmove . from . unGenerically genericMove :: (Generic a, GMovable (Rep a)) => a %1 -> Ur a genericMove = Data.fmap to . gmove . from class GDupable f => GMovable f where gmove :: f p %1 -> Ur (f p) instance GMovable V1 where gmove = \case {} instance GMovable U1 where gmove U1 = Ur U1 instance (GMovable f, GMovable g) => GMovable (f :+: g) where gmove (L1 a) = gmove a & \case (Ur x) -> Ur (L1 x) gmove (R1 a) = gmove a & \case (Ur x) -> Ur (R1 x) instance (GMovable f, GMovable g) => GMovable (f :*: g) where gmove (a :*: b) = gmove a & \case (Ur x) -> gmove b & \case (Ur y) -> Ur (x :*: y) instance Movable c => GMovable (K1 i c) where gmove (K1 c) = lcoerce (move c) instance GMovable f => GMovable (M1 i t f) where gmove (M1 a) = lcoerce (gmove a) instance GMovable (MP1 'Many f) where gmove (MP1 x) = Ur (MP1 x) instance GMovable f => GMovable (MP1 'One f) where gmove (MP1 a) = gmove a & \case Ur x -> Ur (MP1 x) instance GMovable UChar where gmove (UChar c) = Unsafe.toLinear (\x -> Ur (UChar x)) c instance GMovable UDouble where gmove (UDouble c) = Unsafe.toLinear (\x -> Ur (UDouble x)) c instance GMovable UFloat where gmove (UFloat c) = Unsafe.toLinear (\x -> Ur (UFloat x)) c instance GMovable UInt where gmove (UInt c) = Unsafe.toLinear (\x -> Ur (UInt x)) c instance GMovable UWord where gmove (UWord c) = Unsafe.toLinear (\x -> Ur (UWord x)) c