{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
module SizedGrid.Coord.Class where
import SizedGrid.Ordinal
import Control.Lens
import Data.Constraint
import Data.Maybe (fromJust)
import Data.Proxy
import GHC.TypeLits
import Unsafe.Coerce (unsafeCoerce)
coordFromNatCollapse ::
forall a x y. Dict (CoordFromNat (CoordFromNat a x) y ~ CoordFromNat a y)
coordFromNatCollapse = unsafeCoerce (Dict :: Dict (z ~ z))
coordFromNatSame ::
(CoordFromNat a ~ CoordFromNat b) :- (a ~ CoordFromNat b (CoordSized a))
coordFromNatSame = Sub (unsafeCoerce (Dict :: Dict (a ~ a)))
coordSizedCollapse :: forall c n . Dict (CoordSized (CoordFromNat c n) ~ n)
coordSizedCollapse = unsafeCoerce (Dict :: Dict (a ~ a))
class (1 <= CoordSized c, KnownNat (CoordSized c)) => IsCoord c where
type CoordSized c :: Nat
type CoordFromNat c :: (Nat -> *)
asOrdinal :: Iso' c (Ordinal (CoordSized c))
zeroPosition :: c
default zeroPosition :: Monoid c => c
zeroPosition = mempty
sCoordSized :: proxy c -> Proxy (CoordSized c)
sCoordSized _ = Proxy
maxCoordSize :: proxy c -> Integer
maxCoordSize p = natVal (sCoordSized p) - 1
maxCoord :: c
maxCoord = view (re asOrdinal) maxCoord
asSizeProxy ::
c
-> (forall n. (KnownNat n, n + 1 <= (CoordSized c)) =>
Proxy n -> x)
-> x
asSizeProxy c = asSizeProxy (view asOrdinal c)
weakenIsCoord :: IsCoord (CoordFromNat c n) => c -> Maybe (CoordFromNat c n)
weakenIsCoord = fmap (review asOrdinal) . weakenOrdinal . view asOrdinal
strengthenIsCoord ::
(IsCoord (CoordFromNat c n), CoordSized c <= CoordSized (CoordFromNat c n))
=> c
-> CoordFromNat c n
strengthenIsCoord = review asOrdinal . strengthenOrdinal . view asOrdinal
instance (1 <= n, KnownNat n) => IsCoord (Ordinal n) where
type CoordSized (Ordinal n) = n
type CoordFromNat (Ordinal n) = Ordinal
asOrdinal = id
zeroPosition = Ordinal (Proxy @0)
asSizeProxy (Ordinal p) func = func p
maxCoord = fromJust $ numToOrdinal (maxCoordSize (Proxy :: Proxy (Ordinal n)))
allCoordLike :: IsCoord c => [c]
allCoordLike = toListOf (traverse . re asOrdinal) [minBound .. maxBound]