{-# LANGUAGE LinearTypes #-}

module Proarrow.Category.Instance.Linear where

import Data.IORef (newIORef, readIORef, writeIORef)
import Data.Kind (Type)
import Data.Void (Void)
import Prelude (Either (..), undefined)

import Proarrow.Adjunction (Adjunction (..))
import Proarrow.Category.Monoidal (Monoidal (..), MonoidalProfunctor (..), SymMonoidal (..))
import Proarrow.Core (CAT, CategoryOf (..), Is, Profunctor (..), Promonad (..), UN, dimapDefault, type (+->))
import Proarrow.Functor (Functor (..))
import Proarrow.Monoid (Comonoid (..))
import Proarrow.Object.BinaryCoproduct (HasBinaryCoproducts (..))
import Proarrow.Object.BinaryProduct (HasBinaryProducts (..))
import Proarrow.Object.Dual (StarAutonomous (..))
import Proarrow.Object.Exponential (Closed (..))
import Proarrow.Object.Initial (HasInitialObject (..))
import Proarrow.Object.Terminal (HasTerminalObject (..))
import Proarrow.Profunctor.Composition ((:.:) (..))
import Proarrow.Profunctor.Representable (RepCostar (..), Representable (..), dimapRep)
import System.IO.Unsafe (unsafeDupablePerformIO)
import Unsafe.Coerce (unsafeCoerce)

data LINEAR = L Type
type instance UN L (L a) = a

type Linear :: CAT LINEAR
data Linear a b where
  Linear :: {forall x b. Linear ('L x) ('L b) -> x %1 -> b
unLinear :: a %1 -> b} -> Linear (L a) (L b)

instance Profunctor Linear where
  dimap :: forall (c :: LINEAR) (a :: LINEAR) (b :: LINEAR) (d :: LINEAR).
(c ~> a) -> (b ~> d) -> Linear a b -> Linear c d
dimap = (c ~> a) -> (b ~> d) -> Linear a b -> Linear c d
Linear c a -> Linear b d -> Linear a b -> Linear c d
forall {k} (p :: PRO k k) (c :: k) (a :: k) (b :: k) (d :: k).
Promonad p =>
p c a -> p b d -> p a b -> p c d
dimapDefault
  (Ob a, Ob b) => r
r \\ :: forall (a :: LINEAR) (b :: LINEAR) r.
((Ob a, Ob b) => r) -> Linear a b -> r
\\ Linear{} = r
(Ob a, Ob b) => r
r
instance Promonad Linear where
  id :: forall (a :: LINEAR). Ob a => Linear a a
id = (UN 'L a %1 -> UN 'L a) -> Linear ('L (UN 'L a)) ('L (UN 'L a))
forall x b. (x %1 -> b) -> Linear ('L x) ('L b)
Linear \UN 'L a
x -> UN 'L a
x
  Linear a %1 -> b
f . :: forall (b :: LINEAR) (c :: LINEAR) (a :: LINEAR).
Linear b c -> Linear a b -> Linear a c
. Linear a %1 -> b
g = (a %1 -> b) -> Linear ('L a) ('L b)
forall x b. (x %1 -> b) -> Linear ('L x) ('L b)
Linear \a
x -> a %1 -> b
f (a %1 -> b
g a
x)

-- | Category of linear functions.
instance CategoryOf LINEAR where
  type (~>) = Linear
  type Ob (a :: LINEAR) = Is L a

instance MonoidalProfunctor Linear where
  par0 :: Linear Unit Unit
par0 = Linear Unit Unit
Linear ('L ()) ('L ())
forall {k} (p :: PRO k k) (a :: k). (Promonad p, Ob a) => p a a
forall (a :: LINEAR). Ob a => Linear a a
id
  Linear a %1 -> b
f par :: forall (x1 :: LINEAR) (x2 :: LINEAR) (y1 :: LINEAR) (y2 :: LINEAR).
Linear x1 x2 -> Linear y1 y2 -> Linear (x1 ** y1) (x2 ** y2)
`par` Linear a %1 -> b
g = ((a, a) %1 -> (b, b)) -> Linear ('L (a, a)) ('L (b, b))
forall x b. (x %1 -> b) -> Linear ('L x) ('L b)
Linear \(a
x, a
y) -> (a %1 -> b
f a
x, a %1 -> b
g a
y)

instance Monoidal LINEAR where
  type Unit = L ()
  type L a ** L b = L (a, b)
  leftUnitor :: forall (a :: LINEAR). Ob a => (Unit ** a) ~> a
leftUnitor = (((), UN 'L a) %1 -> UN 'L a)
-> Linear ('L ((), UN 'L a)) ('L (UN 'L a))
forall x b. (x %1 -> b) -> Linear ('L x) ('L b)
Linear \((), UN 'L a
x) -> UN 'L a
x
  leftUnitorInv :: forall (a :: LINEAR). Ob a => a ~> (Unit ** a)
leftUnitorInv = (UN 'L a %1 -> ((), UN 'L a))
-> Linear ('L (UN 'L a)) ('L ((), UN 'L a))
forall x b. (x %1 -> b) -> Linear ('L x) ('L b)
Linear \UN 'L a
x -> ((), UN 'L a
x)
  rightUnitor :: forall (a :: LINEAR). Ob a => (a ** Unit) ~> a
rightUnitor = ((UN 'L a, ()) %1 -> UN 'L a)
-> Linear ('L (UN 'L a, ())) ('L (UN 'L a))
forall x b. (x %1 -> b) -> Linear ('L x) ('L b)
Linear \(UN 'L a
x, ()) -> UN 'L a
x
  rightUnitorInv :: forall (a :: LINEAR). Ob a => a ~> (a ** Unit)
rightUnitorInv = (UN 'L a %1 -> (UN 'L a, ()))
-> Linear ('L (UN 'L a)) ('L (UN 'L a, ()))
forall x b. (x %1 -> b) -> Linear ('L x) ('L b)
Linear \UN 'L a
x -> (UN 'L a
x, ())
  associator :: forall (a :: LINEAR) (b :: LINEAR) (c :: LINEAR).
(Ob a, Ob b, Ob c) =>
((a ** b) ** c) ~> (a ** (b ** c))
associator = (((UN 'L a, UN 'L b), UN 'L c) %1 -> (UN 'L a, (UN 'L b, UN 'L c)))
-> Linear
     ('L ((UN 'L a, UN 'L b), UN 'L c))
     ('L (UN 'L a, (UN 'L b, UN 'L c)))
forall x b. (x %1 -> b) -> Linear ('L x) ('L b)
Linear \((UN 'L a
x, UN 'L b
y), UN 'L c
z) -> (UN 'L a
x, (UN 'L b
y, UN 'L c
z))
  associatorInv :: forall (a :: LINEAR) (b :: LINEAR) (c :: LINEAR).
(Ob a, Ob b, Ob c) =>
(a ** (b ** c)) ~> ((a ** b) ** c)
associatorInv = ((UN 'L a, (UN 'L b, UN 'L c)) %1 -> ((UN 'L a, UN 'L b), UN 'L c))
-> Linear
     ('L (UN 'L a, (UN 'L b, UN 'L c)))
     ('L ((UN 'L a, UN 'L b), UN 'L c))
forall x b. (x %1 -> b) -> Linear ('L x) ('L b)
Linear \(UN 'L a
x, (UN 'L b
y, UN 'L c
z)) -> ((UN 'L a
x, UN 'L b
y), UN 'L c
z)

instance SymMonoidal LINEAR where
  swap' :: forall (a :: LINEAR) (a' :: LINEAR) (b :: LINEAR) (b' :: LINEAR).
(a ~> a') -> (b ~> b') -> (a ** b) ~> (b' ** a')
swap' (Linear a %1 -> b
f) (Linear a %1 -> b
g) = ((a, a) %1 -> (b, b)) -> Linear ('L (a, a)) ('L (b, b))
forall x b. (x %1 -> b) -> Linear ('L x) ('L b)
Linear \(a
x, a
y) -> (a %1 -> b
g a
y, a %1 -> b
f a
x)

-- instance TracedMonoidalProfunctor Linear where
--   trace (Linear f) = Linear \x -> let !(y, u) = f (x, u) in y

instance Closed LINEAR where
  type a ~~> b = L (UN L a %1 -> UN L b)
  curry' :: forall (a :: LINEAR) (b :: LINEAR) (c :: LINEAR).
Obj a -> Obj b -> ((a ** b) ~> c) -> a ~> (b ~~> c)
curry' Linear{} Linear{} (Linear a %1 -> b
f) = (b %1 -> b %1 -> b) -> Linear ('L b) ('L (b %1 -> b))
forall x b. (x %1 -> b) -> Linear ('L x) ('L b)
Linear \b
a b
b -> a %1 -> b
f (b
a, b
b)
  uncurry' :: forall (b :: LINEAR) (c :: LINEAR) (a :: LINEAR).
Obj b -> Obj c -> (a ~> (b ~~> c)) -> (a ** b) ~> c
uncurry' Linear{} Linear{} (Linear a %1 -> b
f) = ((a, b) %1 -> b) -> Linear ('L (a, b)) ('L b)
forall x b. (x %1 -> b) -> Linear ('L x) ('L b)
Linear \(a
a, b
b) -> a %1 -> b
f a
a b
b
  Linear a %1 -> b
f ^^^ :: forall (b :: LINEAR) (y :: LINEAR) (x :: LINEAR) (a :: LINEAR).
(b ~> y) -> (x ~> a) -> (a ~~> b) ~> (x ~~> y)
^^^ Linear a %1 -> b
g = ((b %1 -> a) %1 -> a %1 -> b)
-> Linear ('L (b %1 -> a)) ('L (a %1 -> b))
forall x b. (x %1 -> b) -> Linear ('L x) ('L b)
Linear \b %1 -> a
h a
x -> a %1 -> b
f (b %1 -> a
h (a %1 -> b
g a
x))

type Forget :: LINEAR +-> Type
data Forget a b where
  Forget :: (a -> b) -> Forget a (L b)
instance Profunctor Forget where
  dimap :: forall c a (b :: LINEAR) (d :: LINEAR).
(c ~> a) -> (b ~> d) -> Forget a b -> Forget c d
dimap = (c ~> a) -> (b ~> d) -> Forget a b -> Forget c d
forall {j} {k} (p :: j +-> k) (a :: k) (b :: j) (c :: k) (d :: j).
Representable p =>
(c ~> a) -> (b ~> d) -> p a b -> p c d
dimapRep
  (Ob a, Ob b) => r
r \\ :: forall a (b :: LINEAR) r. ((Ob a, Ob b) => r) -> Forget a b -> r
\\ Forget{} = r
(Ob a, Ob b) => r
r
instance Representable Forget where
  type Forget % a = UN L a
  index :: forall a (b :: LINEAR). Forget a b -> a ~> (Forget % b)
index (Forget a -> b
f) = a ~> (Forget % b)
a -> b
f
  tabulate :: forall (b :: LINEAR) a. Ob b => (a ~> (Forget % b)) -> Forget a b
tabulate = (a ~> (Forget % b)) -> Forget a b
(a -> UN 'L b) -> Forget a ('L (UN 'L b))
forall a x. (a -> x) -> Forget a ('L x)
Forget
  repMap :: forall (a :: LINEAR) (b :: LINEAR).
(a ~> b) -> (Forget % a) ~> (Forget % b)
repMap (Linear a %1 -> b
f) UN 'L a
x = a %1 -> b
f a
UN 'L a
x

-- | Forget is a lax monoidal functor
instance MonoidalProfunctor Forget where
  par0 :: Forget Unit Unit
par0 = (() -> ()) -> Forget () ('L ())
forall a x. (a -> x) -> Forget a ('L x)
Forget \() -> ()
  Forget x1 -> b
f par :: forall x1 (x2 :: LINEAR) y1 (y2 :: LINEAR).
Forget x1 x2 -> Forget y1 y2 -> Forget (x1 ** y1) (x2 ** y2)
`par` Forget y1 -> b
g = ((x1, y1) -> (b, b)) -> Forget (x1, y1) ('L (b, b))
forall a x. (a -> x) -> Forget a ('L x)
Forget \(x1
x, y1
y) -> (x1 -> b
f x1
x, y1 -> b
g y1
y)

-- | Forget is also a colax monoidal functor
instance MonoidalProfunctor (RepCostar Forget) where
  par0 :: RepCostar Forget Unit Unit
par0 = ((Forget % 'L ()) ~> ()) -> RepCostar Forget ('L ()) ()
forall {k} {j} (a :: k) (p :: k +-> j) (b :: j).
Ob a =>
((p % a) ~> b) -> RepCostar p a b
RepCostar (Forget % 'L ()) ~> ()
() -> ()
forall a. Ob a => a -> a
forall {k} (p :: PRO k k) (a :: k). (Promonad p, Ob a) => p a a
id
  RepCostar (Forget % x1) ~> x2
f par :: forall (x1 :: LINEAR) x2 (y1 :: LINEAR) y2.
RepCostar Forget x1 x2
-> RepCostar Forget y1 y2 -> RepCostar Forget (x1 ** y1) (x2 ** y2)
`par` RepCostar (Forget % y1) ~> y2
g = ((Forget % 'L (UN 'L x1, UN 'L y1)) ~> (x2, y2))
-> RepCostar Forget ('L (UN 'L x1, UN 'L y1)) (x2, y2)
forall {k} {j} (a :: k) (p :: k +-> j) (b :: j).
Ob a =>
((p % a) ~> b) -> RepCostar p a b
RepCostar \(UN 'L x1
x, UN 'L y1
y) -> ((Forget % x1) ~> x2
UN 'L x1 -> x2
f UN 'L x1
x, (Forget % y1) ~> y2
UN 'L y1 -> y2
g UN 'L y1
y)

data Ur a where
  Ur :: a -> Ur a

counitUr :: Ur a %1 -> a
counitUr :: forall a. Ur a %1 -> a
counitUr (Ur a
a) = a
a

dupUr :: Ur a %1 -> Ur (Ur a)
dupUr :: forall a. Ur a %1 -> Ur (Ur a)
dupUr (Ur a
a) = Ur a -> Ur (Ur a)
forall a. a -> Ur a
Ur (a -> Ur a
forall a. a -> Ur a
Ur a
a)

instance Functor Ur where
  map :: forall a b. (a ~> b) -> Ur a ~> Ur b
map a ~> b
f (Ur a
a) = b -> Ur b
forall a. a -> Ur a
Ur (a ~> b
a -> b
f a
a)

instance Comonoid (L (Ur a)) where
  counit :: 'L (Ur a) ~> Unit
counit = (Ur a %1 -> ()) -> Linear ('L (Ur a)) ('L ())
forall x b. (x %1 -> b) -> Linear ('L x) ('L b)
Linear \(Ur a
_) -> ()
  comult :: 'L (Ur a) ~> ('L (Ur a) ** 'L (Ur a))
comult = (Ur a %1 -> (Ur a, Ur a)) -> Linear ('L (Ur a)) ('L (Ur a, Ur a))
forall x b. (x %1 -> b) -> Linear ('L x) ('L b)
Linear \(Ur a
a) -> (a -> Ur a
forall a. a -> Ur a
Ur a
a, a -> Ur a
forall a. a -> Ur a
Ur a
a)

type Free :: Type +-> LINEAR
data Free a b where
  Free :: (a %1 -> Ur b) -> Free (L a) b
instance Profunctor Free where
  dimap :: forall (c :: LINEAR) (a :: LINEAR) b d.
(c ~> a) -> (b ~> d) -> Free a b -> Free c d
dimap = (c ~> a) -> (b ~> d) -> Free a b -> Free c d
forall {j} {k} (p :: j +-> k) (a :: k) (b :: j) (c :: k) (d :: j).
Representable p =>
(c ~> a) -> (b ~> d) -> p a b -> p c d
dimapRep
  (Ob a, Ob b) => r
r \\ :: forall (a :: LINEAR) b r. ((Ob a, Ob b) => r) -> Free a b -> r
\\ Free{} = r
(Ob a, Ob b) => r
r
instance Representable Free where
  type Free % a = L (Ur a)
  index :: forall (a :: LINEAR) b. Free a b -> a ~> (Free % b)
index (Free a %1 -> Ur b
f) = (a %1 -> Ur b) -> Linear ('L a) ('L (Ur b))
forall x b. (x %1 -> b) -> Linear ('L x) ('L b)
Linear a %1 -> Ur b
f
  tabulate :: forall b (a :: LINEAR). Ob b => (a ~> (Free % b)) -> Free a b
tabulate (Linear a %1 -> b
f) = (a %1 -> Ur b) -> Free ('L a) b
forall x b. (x %1 -> Ur b) -> Free ('L x) b
Free a %1 -> b
a %1 -> Ur b
f
  repMap :: forall a b. (a ~> b) -> (Free % a) ~> (Free % b)
repMap a ~> b
f = (Ur a %1 -> Ur b) -> Linear ('L (Ur a)) ('L (Ur b))
forall x b. (x %1 -> b) -> Linear ('L x) ('L b)
Linear \(Ur a
a) -> b -> Ur b
forall a. a -> Ur a
Ur (a ~> b
a -> b
f a
a)

-- | Free is a lax monoidal functor
instance MonoidalProfunctor Free where
  par0 :: Free Unit Unit
par0 = (() %1 -> Ur ()) -> Free ('L ()) ()
forall x b. (x %1 -> Ur b) -> Free ('L x) b
Free \() -> () -> Ur ()
forall a. a -> Ur a
Ur ()
  Free a %1 -> Ur x2
f par :: forall (x1 :: LINEAR) x2 (y1 :: LINEAR) y2.
Free x1 x2 -> Free y1 y2 -> Free (x1 ** y1) (x2 ** y2)
`par` Free a %1 -> Ur y2
g = ((a, a) %1 -> Ur (x2, y2)) -> Free ('L (a, a)) (x2, y2)
forall x b. (x %1 -> Ur b) -> Free ('L x) b
Free \(a
x, a
y) -> case (a %1 -> Ur x2
f a
x, a %1 -> Ur y2
g a
y) of (Ur x2
a, Ur y2
b) -> (x2, y2) -> Ur (x2, y2)
forall a. a -> Ur a
Ur (x2
a, y2
b)

-- | Free is also a colax monoidal functor
instance MonoidalProfunctor (RepCostar Free) where
  par0 :: RepCostar Free Unit Unit
par0 = ((Free % ()) ~> 'L ()) -> RepCostar Free () ('L ())
forall {k} {j} (a :: k) (p :: k +-> j) (b :: j).
Ob a =>
((p % a) ~> b) -> RepCostar p a b
RepCostar ((Ur () %1 -> ()) -> Linear ('L (Ur ())) ('L ())
forall x b. (x %1 -> b) -> Linear ('L x) ('L b)
Linear (\(Ur ()
_) -> ()))
  RepCostar (Linear a %1 -> b
f) par :: forall x1 (x2 :: LINEAR) y1 (y2 :: LINEAR).
RepCostar Free x1 x2
-> RepCostar Free y1 y2 -> RepCostar Free (x1 ** y1) (x2 ** y2)
`par` RepCostar (Linear a %1 -> b
g) = ((Free % (x1, y1)) ~> 'L (b, b))
-> RepCostar Free (x1, y1) ('L (b, b))
forall {k} {j} (a :: k) (p :: k +-> j) (b :: j).
Ob a =>
((p % a) ~> b) -> RepCostar p a b
RepCostar ((Ur (x1, y1) %1 -> (b, b)) -> Linear ('L (Ur (x1, y1))) ('L (b, b))
forall x b. (x %1 -> b) -> Linear ('L x) ('L b)
Linear \(Ur (x1
x, y1
y)) -> (a %1 -> b
f (x1 -> Ur x1
forall a. a -> Ur a
Ur x1
x), a %1 -> b
g (y1 -> Ur y1
forall a. a -> Ur a
Ur y1
y)))

instance Adjunction Free Forget where
  unit :: forall a. Ob a => (:.:) Forget Free a a
unit = (a -> Ur a) -> Forget a ('L (Ur a))
forall a x. (a -> x) -> Forget a ('L x)
Forget a -> Ur a
forall a. a -> Ur a
Ur Forget a ('L (Ur a)) -> Free ('L (Ur a)) a -> (:.:) Forget Free a a
forall {j} {k} {i} (p :: j +-> k) (a :: k) (b :: j) (q :: i +-> j)
       (c :: i).
p a b -> q b c -> (:.:) p q a c
:.: (Ur a %1 -> Ur a) -> Free ('L (Ur a)) a
forall x b. (x %1 -> Ur b) -> Free ('L x) b
Free \Ur a
x -> Ur a
x
  counit :: (Free :.: Forget) :~> (~>)
counit (Free a %1 -> Ur b
f :.: Forget b -> b
g) = (a %1 -> b) -> Linear ('L a) ('L b)
forall x b. (x %1 -> b) -> Linear ('L x) ('L b)
Linear \a
a -> case a %1 -> Ur b
f a
a of Ur b
b -> b -> b
g b
b

instance HasBinaryCoproducts LINEAR where
  type L a || L b = L (Either a b)
  lft :: forall (a :: LINEAR) (b :: LINEAR). (Ob a, Ob b) => a ~> (a || b)
lft = (UN 'L a %1 -> Either (UN 'L a) (UN 'L b))
-> Linear ('L (UN 'L a)) ('L (Either (UN 'L a) (UN 'L b)))
forall x b. (x %1 -> b) -> Linear ('L x) ('L b)
Linear UN 'L a -> Either (UN 'L a) (UN 'L b)
forall a b. a -> Either a b
Left
  rgt :: forall (a :: LINEAR) (b :: LINEAR). (Ob a, Ob b) => b ~> (a || b)
rgt = (UN 'L b %1 -> Either (UN 'L a) (UN 'L b))
-> Linear ('L (UN 'L b)) ('L (Either (UN 'L a) (UN 'L b)))
forall x b. (x %1 -> b) -> Linear ('L x) ('L b)
Linear UN 'L b -> Either (UN 'L a) (UN 'L b)
forall a b. b -> Either a b
Right
  Linear a %1 -> b
f ||| :: forall (x :: LINEAR) (a :: LINEAR) (y :: LINEAR).
(x ~> a) -> (y ~> a) -> (x || y) ~> a
||| Linear a %1 -> b
g = (Either a a %1 -> b) -> Linear ('L (Either a a)) ('L b)
forall x b. (x %1 -> b) -> Linear ('L x) ('L b)
Linear \case
    Left a
x -> a %1 -> b
f a
x
    Right a
y -> a %1 -> b
g a
y

instance HasInitialObject LINEAR where
  type InitialObject = L Void
  initiate :: forall (a :: LINEAR). Ob a => InitialObject ~> a
initiate = (Void %1 -> UN 'L a) -> Linear ('L Void) ('L (UN 'L a))
forall x b. (x %1 -> b) -> Linear ('L x) ('L b)
Linear \case {}

data Top where
  Top :: a %1 -> Top

data With a b where
  With :: x %1 -> (x %1 -> a) -> (x %1 -> b) -> With a b

urWith :: Ur (With a b) %1 -> (Ur a, Ur b)
urWith :: forall a b. Ur (With a b) %1 -> (Ur a, Ur b)
urWith (Ur (With x
x x %1 -> a
f x %1 -> b
g)) = (a -> Ur a
forall a. a -> Ur a
Ur (x %1 -> a
f x
x), b -> Ur b
forall a. a -> Ur a
Ur (x %1 -> b
g x
x))

instance HasTerminalObject LINEAR where
  type TerminalObject = L Top
  terminate :: forall (a :: LINEAR). Ob a => a ~> TerminalObject
terminate = (UN 'L a %1 -> Top) -> Linear ('L (UN 'L a)) ('L Top)
forall x b. (x %1 -> b) -> Linear ('L x) ('L b)
Linear UN 'L a -> Top
forall x. x -> Top
Top

instance HasBinaryProducts LINEAR where
  type L a && L b = L (With a b)
  fst :: forall (a :: LINEAR) (b :: LINEAR). (Ob a, Ob b) => (a && b) ~> a
fst = (With (UN 'L a) (UN 'L b) %1 -> UN 'L a)
-> Linear ('L (With (UN 'L a) (UN 'L b))) ('L (UN 'L a))
forall x b. (x %1 -> b) -> Linear ('L x) ('L b)
Linear \(With x
x x %1 -> UN 'L a
xa x %1 -> UN 'L b
_) -> x %1 -> UN 'L a
xa x
x
  snd :: forall (a :: LINEAR) (b :: LINEAR). (Ob a, Ob b) => (a && b) ~> b
snd = (With (UN 'L a) (UN 'L b) %1 -> UN 'L b)
-> Linear ('L (With (UN 'L a) (UN 'L b))) ('L (UN 'L b))
forall x b. (x %1 -> b) -> Linear ('L x) ('L b)
Linear \(With x
x x %1 -> UN 'L a
_ x %1 -> UN 'L b
xb) -> x %1 -> UN 'L b
xb x
x
  Linear a %1 -> b
f &&& :: forall (a :: LINEAR) (x :: LINEAR) (y :: LINEAR).
(a ~> x) -> (a ~> y) -> a ~> (x && y)
&&& Linear a %1 -> b
g = (a %1 -> With b b) -> Linear ('L a) ('L (With b b))
forall x b. (x %1 -> b) -> Linear ('L x) ('L b)
Linear \a
x -> a -> (a %1 -> b) -> (a %1 -> b) -> With b b
forall x a b. x -> (x %1 -> a) -> (x %1 -> b) -> With a b
With a
x a %1 -> b
f a %1 -> b
a %1 -> b
g

type Not a = a %1 -> ()

not :: (Not b %1 -> Not a) %1 -> a %1 -> b
not :: forall b a. (Not b %1 -> Not a) %1 -> a %1 -> b
not Not b %1 -> Not a
nbna a
a = Not (Not b) %1 -> b
forall a. Not (Not a) %1 -> a
dn \Not b
nb -> Not b %1 -> Not a
nbna Not b
nb a
a

not' :: (a %1 -> b) %1 -> Not b %1 -> Not a
not' :: forall a b. (a %1 -> b) %1 -> Not b %1 -> Not a
not' a %1 -> b
ab Not b
nb a
a = Not b
nb (a %1 -> b
ab a
a)

newtype Par a b = Par (Not (Not a, Not b))

toPar :: (a, b) %1 -> Par a b
toPar :: forall a b. (a, b) %1 -> Par a b
toPar (a
a, b
b) = Not (Not a, Not b) -> Par a b
forall a b. Not (Not a, Not b) -> Par a b
Par \(Not a
na, Not b
nb) -> case (Not a
na a
a, Not b
nb b
b) of ((), ()) -> ()

pairFst :: (a, b `Par` c) %1 -> (a, b) `Par` c
pairFst :: forall a b c. (a, Par b c) %1 -> Par (a, b) c
pairFst (a
a, Par Not (Not b, Not c)
f) = Not (Not (a, b), Not c) -> Par (a, b) c
forall a b. Not (Not a, Not b) -> Par a b
Par \(Not (a, b)
nab, Not c
nc) -> Not (Not b, Not c)
f (\b
b -> Not (a, b)
nab (a
a, b
b), Not c
nc)

pairSnd :: (a `Par` b, c) %1 -> a `Par` (b, c)
pairSnd :: forall a b c. (Par a b, c) %1 -> Par a (b, c)
pairSnd (Par Not (Not a, Not b)
f, c
c) = Not (Not a, Not (b, c)) -> Par a (b, c)
forall a b. Not (Not a, Not b) -> Par a b
Par \(Not a
na, Not (b, c)
nbc) -> Not (Not a, Not b)
f (Not a
na, \b
b -> Not (b, c)
nbc (b
b, c
c))

parAppL :: (a `Par` b) %1 -> Not a %1 -> b
parAppL :: forall a b. Par a b %1 -> Not a %1 -> b
parAppL (Par Not (Not a, Not b)
f) Not a
na = Not (Not b) %1 -> b
forall a. Not (Not a) %1 -> a
dn \Not b
nb -> Not (Not a, Not b)
f (Not a
na, Not b
nb)

parAppR :: (a `Par` b) %1 -> Not b %1 -> a
parAppR :: forall a b. Par a b %1 -> Not b %1 -> a
parAppR (Par Not (Not a, Not b)
f) Not b
nb = Not (Not a) %1 -> a
forall a. Not (Not a) %1 -> a
dn \Not a
na -> Not (Not a, Not b)
f (Not a
na, Not b
nb)

newtype Quest a = Quest (Not (Ur (Not a)))

notQuest :: Not (Quest a) %1 -> Ur (Not a)
notQuest :: forall a. Not (Quest a) %1 -> Ur (Not a)
notQuest Not (Quest a)
nqa = Not (Not (Ur (Not a))) %1 -> Ur (Not a)
forall a. Not (Not a) %1 -> a
dn \Not (Ur (Not a))
nuna -> Not (Quest a)
nqa (Not (Ur (Not a)) -> Quest a
forall a. Not (Ur (Not a)) -> Quest a
Quest Not (Ur (Not a))
nuna)

unitQuest :: a %1 -> Quest a
unitQuest :: forall a. a %1 -> Quest a
unitQuest a
a = Not (Ur (Not a)) -> Quest a
forall a. Not (Ur (Not a)) -> Quest a
Quest \(Ur Not a
na) -> Not a
na a
a

multQuest :: Quest (Quest a) %1 -> Quest a
multQuest :: forall a. Quest (Quest a) %1 -> Quest a
multQuest (Quest Not (Ur (Not (Quest a)))
f) = Not (Ur (Not a)) -> Quest a
forall a. Not (Ur (Not a)) -> Quest a
Quest \(Ur Not a
na) -> Not (Ur (Not (Quest a)))
f (Not (Quest a) -> Ur (Not (Quest a))
forall a. a -> Ur a
Ur (\(Quest Not (Ur (Not a))
nuna) -> Not (Ur (Not a))
nuna (Not a -> Ur (Not a)
forall a. a -> Ur a
Ur Not a
na)))

questPar :: Par (Quest a) (Quest b) %1 -> Quest (Either a b)
questPar :: forall a b. Par (Quest a) (Quest b) %1 -> Quest (Either a b)
questPar (Par Not (Not (Quest a), Not (Quest b))
f) = Not (Ur (Not (Either a b))) -> Quest (Either a b)
forall a. Not (Ur (Not a)) -> Quest a
Quest (\(Ur Not (Either a b)
g) -> Not (Not (Quest a), Not (Quest b))
f (\(Quest Not (Ur (Not a))
nuna) -> Not (Ur (Not a))
nuna (Not a -> Ur (Not a)
forall a. a -> Ur a
Ur (\a
a -> Not (Either a b)
g (a -> Either a b
forall a b. a -> Either a b
Left a
a))), \(Quest Not (Ur (Not b))
nunb) -> Not (Ur (Not b))
nunb (Not b -> Ur (Not b)
forall a. a -> Ur a
Ur (\b
b -> Not (Either a b)
g (b -> Either a b
forall a b. b -> Either a b
Right b
b)))))

instance StarAutonomous LINEAR where
  type Dual (L a) = L (Not a)
  dual :: forall (a :: LINEAR) (b :: LINEAR). (a ~> b) -> Dual b ~> Dual a
dual (Linear a %1 -> b
f) = ((b %1 -> ()) %1 -> a %1 -> ())
-> Linear ('L (b %1 -> ())) ('L (a %1 -> ()))
forall x b. (x %1 -> b) -> Linear ('L x) ('L b)
Linear (\b %1 -> ()
nb a
a -> b %1 -> ()
nb (a %1 -> b
f a
a))
  dualInv :: forall (a :: LINEAR) (b :: LINEAR).
(Ob a, Ob b) =>
(Dual a ~> Dual b) -> b ~> a
dualInv (Linear a %1 -> b
f) = (UN 'L b %1 -> UN 'L a) -> Linear ('L (UN 'L b)) ('L (UN 'L a))
forall x b. (x %1 -> b) -> Linear ('L x) ('L b)
Linear (\UN 'L b
b -> Not (Not (UN 'L a)) %1 -> UN 'L a
forall a. Not (Not a) %1 -> a
dn (\Not (UN 'L a)
na -> a %1 -> b
f a
Not (UN 'L a)
na UN 'L b
b))
  linDist :: forall (a :: LINEAR) (b :: LINEAR) (c :: LINEAR).
(Ob a, Ob b, Ob c) =>
((a ** b) ~> Dual c) -> a ~> Dual (b ** c)
linDist (Linear a %1 -> b
f) = (UN 'L a %1 -> (UN 'L b, UN 'L c) %1 -> ())
-> Linear ('L (UN 'L a)) ('L ((UN 'L b, UN 'L c) %1 -> ()))
forall x b. (x %1 -> b) -> Linear ('L x) ('L b)
Linear (\UN 'L a
a (UN 'L b
b, UN 'L c
c) -> a %1 -> b
f (UN 'L a
a, UN 'L b
b) UN 'L c
c)
  linDistInv :: forall (a :: LINEAR) (b :: LINEAR) (c :: LINEAR).
(Ob a, Ob b, Ob c) =>
(a ~> Dual (b ** c)) -> (a ** b) ~> Dual c
linDistInv (Linear a %1 -> b
f) = ((a, UN 'L b) %1 -> UN 'L c %1 -> ())
-> Linear ('L (a, UN 'L b)) ('L (UN 'L c %1 -> ()))
forall x b. (x %1 -> b) -> Linear ('L x) ('L b)
Linear (\(a
a, UN 'L b
b) UN 'L c
c -> a %1 -> b
f a
a (UN 'L b
b, UN 'L c
c))

-- | Double negation is possible with linear functions, though using `unsafeDupablePerformIO`.
-- Derived from https://gist.github.com/ant-arctica/7563282c57d9d1ce0c4520c543187932
-- TODO: only tested in GHCi, might get ruined by optimizations
dn :: Not (Not a) %1 -> a
dn :: forall a. Not (Not a) %1 -> a
dn Not (Not a)
nna =
  let ref :: IORef a
ref = IO (IORef a) -> IORef a
forall a. IO a -> a
unsafeDupablePerformIO (a -> IO (IORef a)
forall a. a -> IO (IORef a)
newIORef a
forall a. HasCallStack => a
undefined)
  in case Not (Not a)
nna ((a -> ()) %1 -> Not a
forall a b. (a -> b) %1 -> a %1 -> b
unsafeLinear (IORef a -> a -> ()
forall {a}. IORef a -> a -> ()
fill IORef a
forall {a}. IORef a
ref)) of () -> IO a -> a
forall a. IO a -> a
unsafeDupablePerformIO (IORef a -> IO a
forall a. IORef a -> IO a
readIORef IORef a
forall {a}. IORef a
ref)
  where
    fill :: IORef a -> a -> ()
fill IORef a
ref a
x = IO () -> ()
forall a. IO a -> a
unsafeDupablePerformIO (IORef a -> a -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef a
ref a
x)

unsafeLinear :: (a -> b) %1 -> (a %1 -> b)
unsafeLinear :: forall a b. (a -> b) %1 -> a %1 -> b
unsafeLinear = (Any -> Any) -> (a -> b) %1 -> a %1 -> b
forall a b. a -> b
unsafeCoerce Any -> Any
forall a b. a -> b
unsafeCoerce

unit :: L () ~> L (Par a (Not a))
unit :: forall a. 'L () ~> 'L (Par a (Not a))
unit = (() %1 -> Par a (a %1 -> ()))
-> Linear ('L ()) ('L (Par a (a %1 -> ())))
forall x b. (x %1 -> b) -> Linear ('L x) ('L b)
Linear \() -> Not (a %1 -> (), Not (a %1 -> ())) -> Par a (a %1 -> ())
forall a b. Not (Not a, Not b) -> Par a b
Par \(a %1 -> ()
na, Not (a %1 -> ())
nna) -> Not (a %1 -> ())
nna a %1 -> ()
na

counit :: L (Not a, a) ~> L ()
counit :: forall a. 'L (Not a, a) ~> 'L ()
counit = ((a %1 -> (), a) %1 -> ()) -> Linear ('L (a %1 -> (), a)) ('L ())
forall x b. (x %1 -> b) -> Linear ('L x) ('L b)
Linear \(a %1 -> ()
na, a
a) -> a %1 -> ()
na a
a


type p !~> q = forall a b. p a b %1 -> q a b

type NegComp :: (j +-> k) -> (i +-> j) -> (i +-> k)
data NegComp p q a c where
  NegComp :: (forall b. Par (p a b) (q b c)) %1 -> NegComp p q a c

newtype Neg p a b = Neg (Not (p b a))

getNeg :: Neg p a b %1 -> Not (p b a)
getNeg :: forall {k} {k} (p :: k -> k -> Type) (a :: k) (b :: k).
Neg p a b %1 -> Not (p b a)
getNeg (Neg Not (p b a)
f) = Not (p b a)
f

conv1 :: NegComp p q !~> Neg (Neg q :.: Neg p)
conv1 :: forall {k} {k} {k} (p :: k +-> k) (q :: k +-> k) (a :: k) (b :: k).
NegComp p q a b %1 -> Neg (Neg q :.: Neg p) a b
conv1 (NegComp forall (b :: k). Par (p a b) (q b b)
e) = Not ((:.:) (Neg q) (Neg p) b a) -> Neg (Neg q :.: Neg p) a b
forall {k} {k} (p :: k -> k -> Type) (a :: k) (b :: k).
Not (p b a) -> Neg p a b
Neg \(Neg Not (q b b)
nq :.: Neg Not (p a b)
np) -> case Par (p a b) (q b b)
forall (b :: k). Par (p a b) (q b b)
e of Par Not (Not (p a b), Not (q b b))
e' -> Not (Not (p a b), Not (q b b))
e' (Not (p a b)
np, Not (q b b)
nq)

conv2 :: Neg (Neg q :.: Neg p) !~> NegComp p q
conv2 :: forall {j} {i} {k} (q :: j -> i -> Type) (p :: k -> j -> Type)
       (a :: k) (b :: i).
Neg (Neg q :.: Neg p) a b %1 -> NegComp p q a b
conv2 (Neg Not ((:.:) (Neg q) (Neg p) b a)
f) = (forall (b :: j). Par (p a b) (q b b)) -> NegComp p q a b
forall {j} {k} {i} (p :: j +-> k) (a :: k) (q :: i +-> j) (c :: i).
(forall (b :: j). Par (p a b) (q b c)) -> NegComp p q a c
NegComp (Not (Not (p a b), Not (q b b)) -> Par (p a b) (q b b)
forall a b. Not (Not a, Not b) -> Par a b
Par (\(Not (p a b)
np, Not (q b b)
nq) -> Not ((:.:) (Neg q) (Neg p) b a)
f (Not (q b b) -> Neg q b b
forall {k} {k} (p :: k -> k -> Type) (a :: k) (b :: k).
Not (p b a) -> Neg p a b
Neg Not (q b b)
nq Neg q b b -> Neg p b a -> (:.:) (Neg q) (Neg p) b a
forall {j} {k} {i} (p :: j +-> k) (a :: k) (b :: j) (q :: i +-> j)
       (c :: i).
p a b -> q b c -> (:.:) p q a c
:.: Not (p a b) -> Neg p b a
forall {k} {k} (p :: k -> k -> Type) (a :: k) (b :: k).
Not (p b a) -> Neg p a b
Neg Not (p a b)
np)))

asCocat :: (Neg p :.: Neg p !~> Neg p) -> p !~> NegComp p p
asCocat :: forall {i} (p :: i -> i -> Type).
((Neg p :.: Neg p) !~> Neg p) -> p !~> NegComp p p
asCocat (Neg p :.: Neg p) !~> Neg p
comp p a b
p = (forall (b :: i). Par (p a b) (p b b)) -> NegComp p p a b
forall {j} {k} {i} (p :: j +-> k) (a :: k) (q :: i +-> j) (c :: i).
(forall (b :: j). Par (p a b) (q b c)) -> NegComp p q a c
NegComp (Not (Not (p a b), Not (p b b)) -> Par (p a b) (p b b)
forall a b. Not (Not a, Not b) -> Par a b
Par \(Not (p a b)
np1, Not (p b b)
np2) -> Neg p b a %1 -> Not (p a b)
forall {k} {k} (p :: k -> k -> Type) (a :: k) (b :: k).
Neg p a b %1 -> Not (p b a)
getNeg ((:.:) (Neg p) (Neg p) b a %1 -> Neg p b a
(Neg p :.: Neg p) !~> Neg p
comp (Not (p b b) -> Neg p b b
forall {k} {k} (p :: k -> k -> Type) (a :: k) (b :: k).
Not (p b a) -> Neg p a b
Neg Not (p b b)
np2 Neg p b b -> Neg p b a -> (:.:) (Neg p) (Neg p) b a
forall {j} {k} {i} (p :: j +-> k) (a :: k) (b :: j) (q :: i +-> j)
       (c :: i).
p a b -> q b c -> (:.:) p q a c
:.: Not (p a b) -> Neg p b a
forall {k} {k} (p :: k -> k -> Type) (a :: k) (b :: k).
Not (p b a) -> Neg p a b
Neg Not (p a b)
np1)) p a b
p)