linear-base-0.1.0: src/Data/Unrestricted/Internal/Instances.hs
{-# OPTIONS_GHC -Wno-orphans #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LinearTypes #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeApplications #-}
-- | This module exports instances of Consumable, Dupable and Movable
--
-- We export instances in this module to avoid a circular dependence
-- and keep things clean. Movable depends on the defintion of Ur yet
-- many instances of Movable which we might have put in the module with
-- Movable depend on Ur. So, we just put the instances of Movable and the
-- other classes (for cleanness) in this module to avoid this dependence.
module Data.Unrestricted.Internal.Instances where
import Data.Unrestricted.Internal.Consumable
import Data.Unrestricted.Internal.Dupable
import Data.Unrestricted.Internal.Movable
import Data.Unrestricted.Internal.Ur
import qualified Data.Functor.Linear.Internal.Functor as Data
import qualified Data.Functor.Linear.Internal.Applicative as Data
import GHC.Types hiding (Any)
import Data.Monoid.Linear
import Data.List.NonEmpty
import qualified Prelude
import qualified Unsafe.Linear as Unsafe
import Data.V.Linear ()
instance Consumable () where
consume () = ()
instance Dupable () where
dupV () = Data.pure ()
instance Movable () where
move () = Ur ()
instance Consumable Bool where
consume True = ()
consume False = ()
instance Dupable Bool where
dupV True = Data.pure True
dupV False = Data.pure False
instance Movable Bool where
move True = Ur True
move False = Ur False
instance Consumable Int where
-- /!\ 'Int#' is an unboxed unlifted data-types, therefore it cannot have any
-- linear values hidden in a closure anywhere. Therefore it is safe to call
-- non-linear functions linearly on this type: there is no difference between
-- copying an 'Int#' and using it several times. /!\
consume (I# i) = Unsafe.toLinear (\_ -> ()) i
instance Dupable Int where
-- /!\ 'Int#' is an unboxed unlifted data-types, therefore it cannot have any
-- linear values hidden in a closure anywhere. Therefore it is safe to call
-- non-linear functions linearly on this type: there is no difference between
-- copying an 'Int#' and using it several times. /!\
dupV (I# i) = Unsafe.toLinear (\j -> Data.pure (I# j)) i
instance Movable Int where
-- /!\ 'Int#' is an unboxed unlifted data-types, therefore it cannot have any
-- linear values hidden in a closure anywhere. Therefore it is safe to call
-- non-linear functions linearly on this type: there is no difference between
-- copying an 'Int#' and using it several times. /!\
move (I# i) = Unsafe.toLinear (\j -> Ur (I# j)) i
instance Consumable Double where
-- /!\ 'Double#' is an unboxed unlifted data-types, therefore it cannot have any
-- linear values hidden in a closure anywhere. Therefore it is safe to call
-- non-linear functions linearly on this type: there is no difference between
-- copying an 'Double#' and using it several times. /!\
consume (D# i) = Unsafe.toLinear (\_ -> ()) i
instance Dupable Double where
-- /!\ 'Double#' is an unboxed unlifted data-types, therefore it cannot have any
-- linear values hidden in a closure anywhere. Therefore it is safe to call
-- non-linear functions linearly on this type: there is no difference between
-- copying an 'Double#' and using it several times. /!\
dupV (D# i) = Unsafe.toLinear (\j -> Data.pure (D# j)) i
instance Movable Double where
-- /!\ 'Double#' is an unboxed unlifted data-types, therefore it cannot have any
-- linear values hidden in a closure anywhere. Therefore it is safe to call
-- non-linear functions linearly on this type: there is no difference between
-- copying an 'Double#' and using it several times. /!\
move (D# i) = Unsafe.toLinear (\j -> Ur (D# j)) i
instance Consumable Char where
consume (C# c) = Unsafe.toLinear (\_ -> ()) c
instance Dupable Char where
dupV (C# c) = Unsafe.toLinear (\x -> Data.pure (C# x)) c
instance Movable Char where
move (C# c) = Unsafe.toLinear (\x -> Ur (C# x)) c
instance Consumable Ordering where
consume LT = ()
consume GT = ()
consume EQ = ()
instance Dupable Ordering where
dup2 LT = (LT, LT)
dup2 GT = (GT, GT)
dup2 EQ = (EQ, EQ)
instance Movable Ordering where
move LT = Ur LT
move GT = Ur GT
move EQ = Ur EQ
-- TODO: instances for longer primitive tuples
-- TODO: default instances based on the Generic framework
instance (Consumable a, Consumable b) => Consumable (a, b) where
consume (a, b) = consume a `lseq` consume b
instance (Dupable a, Dupable b) => Dupable (a, b) where
dupV (a, b) = (,) Data.<$> dupV a Data.<*> dupV b
instance (Movable a, Movable b) => Movable (a, b) where
move (a, b) = (,) Data.<$> move a Data.<*> move b
instance (Consumable a, Consumable b, Consumable c) => Consumable (a, b, c) where
consume (a, b, c) = consume a `lseq` consume b `lseq` consume c
instance (Dupable a, Dupable b, Dupable c) => Dupable (a, b, c) where
dupV (a, b, c) = (,,) Data.<$> dupV a Data.<*> dupV b Data.<*> dupV c
instance (Movable a, Movable b, Movable c) => Movable (a, b, c) where
move (a, b, c) = (,,) Data.<$> move a Data.<*> move b Data.<*> move c
instance Consumable a => Consumable (Prelude.Maybe a) where
consume Prelude.Nothing = ()
consume (Prelude.Just x) = consume x
instance Dupable a => Dupable (Prelude.Maybe a) where
dupV Prelude.Nothing = Data.pure Prelude.Nothing
dupV (Prelude.Just x) = Data.fmap Prelude.Just (dupV x)
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 (Consumable a, Consumable b) => Consumable (Prelude.Either a b) where
consume (Prelude.Left a) = consume a
consume (Prelude.Right b) = consume b
instance (Dupable a, Dupable b) => Dupable (Prelude.Either a b) where
dupV (Prelude.Left a) = Data.fmap Prelude.Left (dupV a)
dupV (Prelude.Right b) = Data.fmap Prelude.Right (dupV b)
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 Consumable a => Consumable [a] where
consume [] = ()
consume (a:l) = consume a `lseq` consume l
instance Dupable a => Dupable [a] where
dupV [] = Data.pure []
dupV (a:l) = (:) Data.<$> dupV a Data.<*> dupV l
instance Movable a => Movable [a] where
move [] = Ur []
move (a:l) = (:) Data.<$> move a Data.<*> move l
instance Consumable a => Consumable (NonEmpty a) where
consume (x :| xs) = consume x `lseq` consume xs
instance Dupable a => Dupable (NonEmpty a) where
dupV (x :| xs) = (:|) Data.<$> dupV x Data.<*> dupV xs
instance Movable a => Movable (NonEmpty a) where
move (x :| xs) = (:|) Data.<$> move x Data.<*> move xs
instance Consumable (Ur a) where
consume (Ur _) = ()
instance Dupable (Ur a) where
dupV (Ur a) = Data.pure (Ur a)
instance Movable (Ur a) where
move (Ur a) = Ur (Ur a)
instance Prelude.Functor Ur where
fmap f (Ur a) = Ur (f a)
instance Prelude.Applicative Ur where
pure = Ur
Ur f <*> Ur x = Ur (f x)
instance Data.Functor Ur where
fmap f (Ur a) = Ur (f a)
instance Data.Applicative Ur where
pure = Ur
Ur f <*> Ur x = Ur (f x)
instance Prelude.Foldable Ur where
foldMap f (Ur x) = f x
instance Prelude.Traversable Ur where
sequenceA (Ur x) = Prelude.fmap Ur x
-- Some stock instances
deriving instance Consumable a => Consumable (Sum a)
deriving instance Dupable a => Dupable (Sum a)
deriving instance Movable a => Movable (Sum a)
deriving instance Consumable a => Consumable (Product a)
deriving instance Dupable a => Dupable (Product a)
deriving instance Movable a => Movable (Product a)
deriving instance Consumable All
deriving instance Dupable All
deriving instance Movable All
deriving instance Consumable Any
deriving instance Dupable Any
deriving instance Movable Any
newtype MovableMonoid a = MovableMonoid a
deriving (Prelude.Semigroup, Prelude.Monoid)
instance (Movable a, Prelude.Semigroup a) => Semigroup (MovableMonoid a) where
MovableMonoid a <> MovableMonoid b = MovableMonoid (combine (move a) (move b))
where combine :: Prelude.Semigroup a => Ur a %1-> Ur a %1-> a
combine (Ur x) (Ur y) = x Prelude.<> y
instance (Movable a, Prelude.Monoid a) => Monoid (MovableMonoid a)