packages feed

moonlight-category-0.1.0.0: test/abstract/DoubleCategorySpec.hs

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeApplications #-}

module DoubleCategorySpec
  ( tests,
  )
where

import Data.Proxy (Proxy (..))
import Moonlight.Category (DoubleCategory (..), interchangeLaw)
import Moonlight.Category.Test.DoubleFixture
  ( SymbolicDouble,
    SymbolicHorizontal (..),
    SymbolicObject (..),
    SymbolicSquare (..),
    SymbolicVertical (..),
  )
import Test.Tasty (TestTree, testGroup)
import Test.Tasty.HUnit ((@?=), testCase)

tests :: TestTree
tests =
  testGroup
    "DoubleCategory"
    [ testCase "interchange law holds for a symbolic 2x2 grid" testInterchangeLaw,
      testCase "typed identities are neutral on symbolic morphisms" testIdentity
    ]

horizontalArrow :: String -> SymbolicHorizontal String source target
horizontalArrow labelValue = SymbolicHorizontal [labelValue]

verticalArrow :: String -> SymbolicVertical String source target
verticalArrow labelValue = SymbolicVertical [labelValue]

northWestSquare :: SymbolicSquare String 'ObjectA 'ObjectB 'ObjectD 'ObjectE
northWestSquare =
  SymbolicSquare
    { symbolicSquareTop = horizontalArrow "top-west",
      symbolicSquareBottom = horizontalArrow "middle-west",
      symbolicSquareLeft = verticalArrow "left-north",
      symbolicSquareRight = verticalArrow "middle-north"
    }

northEastSquare :: SymbolicSquare String 'ObjectB 'ObjectC 'ObjectE 'ObjectF
northEastSquare =
  SymbolicSquare
    { symbolicSquareTop = horizontalArrow "top-east",
      symbolicSquareBottom = horizontalArrow "middle-east",
      symbolicSquareLeft = verticalArrow "middle-north",
      symbolicSquareRight = verticalArrow "right-north"
    }

southWestSquare :: SymbolicSquare String 'ObjectD 'ObjectE 'ObjectG 'ObjectH
southWestSquare =
  SymbolicSquare
    { symbolicSquareTop = horizontalArrow "middle-west",
      symbolicSquareBottom = horizontalArrow "bottom-west",
      symbolicSquareLeft = verticalArrow "left-south",
      symbolicSquareRight = verticalArrow "middle-south"
    }

southEastSquare :: SymbolicSquare String 'ObjectE 'ObjectF 'ObjectH 'ObjectI
southEastSquare =
  SymbolicSquare
    { symbolicSquareTop = horizontalArrow "middle-east",
      symbolicSquareBottom = horizontalArrow "bottom-east",
      symbolicSquareLeft = verticalArrow "middle-south",
      symbolicSquareRight = verticalArrow "right-south"
    }

testInterchangeLaw :: IO ()
testInterchangeLaw =
  interchangeLaw @SymbolicObject @(SymbolicDouble String) northWestSquare northEastSquare southWestSquare southEastSquare
    @?= Just True

testIdentity :: IO ()
testIdentity = do
  composeHorizontal @SymbolicObject @(SymbolicDouble String) (horizontalIdentity @SymbolicObject @(SymbolicDouble String) (Proxy @'ObjectB)) (horizontalArrow "edge" :: SymbolicHorizontal String 'ObjectA 'ObjectB)
    @?= Just (horizontalArrow "edge")
  composeVertical @SymbolicObject @(SymbolicDouble String) (verticalIdentity @SymbolicObject @(SymbolicDouble String) (Proxy @'ObjectB)) (verticalArrow "edge" :: SymbolicVertical String 'ObjectA 'ObjectB)
    @?= Just (verticalArrow "edge")