packages feed

data-category-0.11: Data/Category/Fin.hs

{-# LANGUAGE TypeFamilies, GADTs, PolyKinds, DataKinds, FlexibleInstances, FlexibleContexts, UndecidableInstances, NoImplicitPrelude #-}
{-# LANGUAGE EmptyCase, TypeApplications, ScopedTypeVariables, TypeOperators #-}
module Data.Category.Fin where

import Data.Category
import Data.Category.Limit
import Data.Category.CartesianClosed

data Nat = Z | S Nat

data Fin n where
  FZ :: Fin ('S n)
  FS :: Fin n -> Fin ('S n)

data LTE (n :: Nat) (a :: Fin n) (b :: Fin n) where
  ZEQ :: LTE ('S m) 'FZ 'FZ
  ZLT :: LTE ('S m) 'FZ  b -> LTE ('S ('S m))  'FZ    ('FS b)
  SLT :: LTE ('S m)  a   b -> LTE ('S ('S m)) ('FS a) ('FS b)

instance Category (LTE n) where
  src ZEQ = ZEQ
  src (ZLT _) = ZEQ
  src (SLT a) = SLT (src a)
  tgt ZEQ = ZEQ
  tgt (ZLT a) = SLT (tgt a)
  tgt (SLT a) = SLT (tgt a)
  ZEQ . a = a
  a . ZEQ = a
  SLT a . ZLT b = ZLT (a . b)
  SLT a . SLT b = SLT (a . b)

instance HasInitialObject (LTE ('S n)) where
  type InitialObject (LTE ('S n)) = 'FZ
  initialObject = ZEQ
  initialize ZEQ = ZEQ
  initialize (SLT a) = ZLT (initialize a)

instance HasTerminalObject (LTE ('S 'Z)) where
  type TerminalObject (LTE ('S 'Z)) = 'FZ
  terminalObject = ZEQ
  terminate ZEQ = ZEQ

instance HasTerminalObject (LTE ('S n)) => HasTerminalObject (LTE ('S ('S n))) where
  type TerminalObject (LTE ('S ('S n))) = 'FS (TerminalObject (LTE ('S n)))
  terminalObject = SLT terminalObject
  terminate ZEQ = ZLT (terminate ZEQ)
  terminate (SLT a) = SLT (terminate a)

instance HasBinaryCoproducts (LTE ('S 'Z)) where
  type BinaryCoproduct (LTE ('S 'Z)) 'FZ 'FZ = 'FZ
  inj1 ZEQ ZEQ = ZEQ
  inj2 ZEQ ZEQ = ZEQ
  ZEQ ||| ZEQ = ZEQ

instance HasBinaryCoproducts (LTE ('S n)) => HasBinaryCoproducts (LTE ('S ('S n))) where
  type BinaryCoproduct (LTE ('S ('S n))) 'FZ 'FZ = 'FZ
  type BinaryCoproduct (LTE ('S ('S n))) 'FZ ('FS b) = 'FS (BinaryCoproduct (LTE ('S n)) 'FZ b)
  type BinaryCoproduct (LTE ('S ('S n))) ('FS a) 'FZ = 'FS (BinaryCoproduct (LTE ('S n)) a 'FZ)
  type BinaryCoproduct (LTE ('S ('S n))) ('FS a) ('FS b) = 'FS (BinaryCoproduct (LTE ('S n)) a b)
  inj1 ZEQ ZEQ = ZEQ
  inj1 ZEQ (SLT a) = ZLT (inj1 ZEQ a)
  inj1 (SLT a) ZEQ = SLT (inj1 a ZEQ)
  inj1 (SLT a) (SLT b) = SLT (inj1 a b)
  inj2 ZEQ ZEQ = ZEQ
  inj2 ZEQ (SLT a) = SLT (inj2 ZEQ a)
  inj2 (SLT a) ZEQ = ZLT (inj2 a ZEQ)
  inj2 (SLT a) (SLT b) = SLT (inj2 a b)
  ZEQ ||| ZEQ = ZEQ
  ZLT a ||| ZLT b = ZLT (case a ||| b of { ZEQ -> ZEQ; ZLT n -> ZLT n })
  ZLT a ||| SLT b = SLT (a ||| b)
  SLT a ||| ZLT b = SLT (a ||| b)
  SLT a ||| SLT b = SLT (a ||| b)

instance HasBinaryProducts (LTE ('S 'Z)) where
  type BinaryProduct (LTE ('S 'Z)) 'FZ 'FZ = 'FZ
  proj1 ZEQ ZEQ = ZEQ
  proj2 ZEQ ZEQ = ZEQ
  ZEQ &&& ZEQ = ZEQ

instance HasBinaryProducts (LTE ('S n)) => HasBinaryProducts (LTE ('S ('S n))) where
  type BinaryProduct (LTE ('S ('S n))) 'FZ 'FZ = 'FZ
  type BinaryProduct (LTE ('S ('S n))) 'FZ ('FS b) = 'FZ
  type BinaryProduct (LTE ('S ('S n))) ('FS a) 'FZ = 'FZ
  type BinaryProduct (LTE ('S ('S n))) ('FS a) ('FS b) = 'FS (BinaryProduct (LTE ('S n)) a b)
  proj1 ZEQ ZEQ = ZEQ
  proj1 ZEQ (SLT _) = ZEQ
  proj1 (SLT a) ZEQ = ZLT (case proj1 a ZEQ of { ZEQ -> ZEQ; ZLT n -> ZLT n })
  proj1 (SLT a) (SLT b) = SLT (proj1 a b)
  proj2 ZEQ ZEQ = ZEQ
  proj2 ZEQ (SLT a) = ZLT (case proj2 ZEQ a of { ZEQ -> ZEQ; ZLT n -> ZLT n })
  proj2 (SLT _) ZEQ = ZEQ
  proj2 (SLT a) (SLT b) = SLT (proj2 a b)
  ZEQ &&& ZEQ = ZEQ
  ZEQ &&& ZLT _ = ZEQ
  ZLT _ &&& ZEQ = ZEQ
  ZLT a &&& ZLT b = ZLT (a &&& b)
  SLT a &&& SLT b = SLT (a &&& b)

data Proof a n where
  Proof :: (BinaryProduct (LTE ('S n)) 'FZ a ~ 'FZ, BinaryProduct (LTE ('S n)) a 'FZ ~ 'FZ) => Proof a n
proof :: Obj (LTE ('S n)) a -> Proof a n
proof = proof -- trust me

instance CartesianClosed (LTE ('S 'Z)) where
  type Exponential (LTE ('S 'Z)) 'FZ 'FZ = 'FZ
  apply ZEQ ZEQ = ZEQ
  tuple ZEQ ZEQ = ZEQ
  ZEQ ^^^ ZEQ = ZEQ

-- b -> c = max(a: min(a, b) <= c)
-- → 0 1 2 3
--  +-------
-- 0|3 3 3 3
-- 1|0 3 3 3
-- 2|0 1 3 3
-- 3|0 1 2 3
instance CartesianClosed (LTE ('S n)) => CartesianClosed (LTE ('S ('S n))) where
  type Exponential (LTE ('S ('S n))) 'FZ 'FZ = 'FS (Exponential (LTE ('S n)) 'FZ 'FZ)
  type Exponential (LTE ('S ('S n))) 'FZ ('FS b) = 'FS (Exponential (LTE ('S n)) 'FZ b)
  type Exponential (LTE ('S ('S n))) ('FS a) 'FZ = 'FZ
  type Exponential (LTE ('S ('S n))) ('FS a) ('FS b) = 'FS (Exponential (LTE ('S n)) a b)
  apply ZEQ ZEQ = ZEQ
  apply ZEQ (SLT a) = ZLT (case apply ZEQ a of { ZEQ -> ZEQ; ZLT n -> ZLT n })
  apply (SLT _) ZEQ = ZEQ
  apply (SLT a) (SLT b) = SLT (apply a b)
  tuple ZEQ ZEQ = case proof (ZEQ @n) of Proof -> ZLT (tuple ZEQ ZEQ)
  tuple ZEQ (SLT a) = case proof (src a) of Proof -> SLT (tuple ZEQ a)
  tuple (SLT _) ZEQ = ZEQ
  tuple (SLT a) (SLT b) = SLT (tuple a b)
  ZEQ ^^^ ZEQ = SLT (ZEQ ^^^ ZEQ)
  ZEQ ^^^ ZLT a = ZLT (initialize (tgt (ZEQ ^^^ a)))
  ZEQ ^^^ SLT _ = ZEQ
  ZLT a ^^^ ZEQ = SLT (a ^^^ ZEQ)
  ZLT a ^^^ ZLT b = ZLT (initialize (tgt (a ^^^ b)))
  ZLT a ^^^ SLT b = ZLT (initialize (tgt (a ^^^ b)))
  SLT a ^^^ ZEQ = SLT (a ^^^ ZEQ)
  SLT a ^^^ ZLT b = SLT (a ^^^ b)
  SLT a ^^^ SLT b = SLT (a ^^^ b)