{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE UnboxedTuples #-}
{-# OPTIONS_HADDOCK not-home #-}
module Cleff.Internal.Stack
( Effect
, Stack
, HandlerPtr (HandlerPtr, unHandlerPtr)
, type (++)
, empty
, cons
, concat
, KnownList
, head
, take
, tail
, drop
, (:>)
, (:>>)
, Subset
, index
, pick
, update
) where
import Data.Coerce (coerce)
import Data.Kind (Constraint, Type)
import Data.PrimVec (PrimVec)
import qualified Data.PrimVec as Vec
import GHC.TypeLits (ErrorMessage (ShowType, Text, (:<>:)), TypeError)
import Prelude hiding (concat, drop, head, tail, take)
type Effect = (Type -> Type) -> Type -> Type
type role Stack nominal
newtype Stack (es :: [Effect]) = Stack (PrimVec Int)
type role HandlerPtr nominal
newtype HandlerPtr (e :: Effect) = HandlerPtr { HandlerPtr e -> Int
unHandlerPtr :: Int }
unreifiable :: String -> String -> String -> a
unreifiable :: String -> String -> String -> a
unreifiable String
clsName String
funName String
comp = String -> a
forall a. HasCallStack => String -> a
error (String -> a) -> String -> a
forall a b. (a -> b) -> a -> b
$
String
funName String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
": Attempting to access " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
comp String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
" without a reflected value. This is perhaps because you are trying \
\to define an instance for the '" String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
clsName String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"' typeclass, which you should not be doing whatsoever. If that or \
\other shenanigans seem unlikely, please report this as a bug."
empty :: Stack '[]
empty :: Stack '[]
empty = PrimVec Int -> Stack '[]
coerce (Prim Int => PrimVec Int
forall a. Prim a => PrimVec a
Vec.empty @Int)
cons :: HandlerPtr e -> Stack es -> Stack (e : es)
cons :: HandlerPtr e -> Stack es -> Stack (e : es)
cons = (Int -> PrimVec Int -> PrimVec Int)
-> HandlerPtr e -> Stack es -> Stack (e : es)
coerce (Prim Int => Int -> PrimVec Int -> PrimVec Int
forall a. Prim a => a -> PrimVec a -> PrimVec a
Vec.cons @Int)
type family xs ++ ys where
'[] ++ ys = ys
(x : xs) ++ ys = x : (xs ++ ys)
infixr 5 ++
concat :: Stack es -> Stack es' -> Stack (es ++ es')
concat :: Stack es -> Stack es' -> Stack (es ++ es')
concat = (PrimVec Int -> PrimVec Int -> PrimVec Int)
-> Stack es -> Stack es' -> Stack (es ++ es')
coerce (Prim Int => PrimVec Int -> PrimVec Int -> PrimVec Int
forall a. Prim a => PrimVec a -> PrimVec a -> PrimVec a
Vec.concat @Int)
tail :: Stack (e : es) -> Stack es
tail :: Stack (e : es) -> Stack es
tail = (PrimVec Int -> PrimVec Int) -> Stack (e : es) -> Stack es
coerce (PrimVec Int -> PrimVec Int
forall a. PrimVec a -> PrimVec a
Vec.tail @Int)
class KnownList (es :: [Effect]) where
reifyLen :: Int
reifyLen = String -> String -> String -> Int
forall a. String -> String -> String -> a
unreifiable String
"KnownList" String
"Cleff.Internal.Stack.reifyLen" String
"the length of a type-level list"
instance KnownList '[] where
reifyLen :: Int
reifyLen = Int
0
instance KnownList es => KnownList (e : es) where
reifyLen :: Int
reifyLen = Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ KnownList es => Int
forall (es :: [Effect]). KnownList es => Int
reifyLen @es
drop :: ∀ es es'. KnownList es => Stack (es ++ es') -> Stack es'
drop :: Stack (es ++ es') -> Stack es'
drop = (Int -> PrimVec Int -> PrimVec Int)
-> Int -> Stack (es ++ es') -> Stack es'
coerce (Int -> PrimVec Int -> PrimVec Int
forall a. Int -> PrimVec a -> PrimVec a
Vec.drop @Int) (KnownList es => Int
forall (es :: [Effect]). KnownList es => Int
reifyLen @es)
head :: Stack (e : es) -> HandlerPtr e
head :: Stack (e : es) -> HandlerPtr e
head = (PrimVec Int -> Int) -> Stack (e : es) -> HandlerPtr e
coerce (Prim Int => PrimVec Int -> Int
forall a. Prim a => PrimVec a -> a
Vec.head @Int)
take :: ∀ es es'. KnownList es => Stack (es ++ es') -> Stack es
take :: Stack (es ++ es') -> Stack es
take = (Int -> PrimVec Int -> PrimVec Int)
-> Int -> Stack (es ++ es') -> Stack es
coerce (Prim Int => Int -> PrimVec Int -> PrimVec Int
forall a. Prim a => Int -> PrimVec a -> PrimVec a
Vec.take @Int) (KnownList es => Int
forall (es :: [Effect]). KnownList es => Int
reifyLen @es)
class (e :: Effect) :> (es :: [Effect]) where
reifyIndex :: Int
reifyIndex = String -> String -> String -> Int
forall a. String -> String -> String -> a
unreifiable String
"Elem" String
"Cleff.Internal.Stack.reifyIndex" String
"the index of an effect in the effect stack"
infix 0 :>
instance {-# OVERLAPPING #-} e :> e : es where
reifyIndex :: Int
reifyIndex = Int
0
instance e :> es => e :> e' : es where
reifyIndex :: Int
reifyIndex = Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ (e :> es) => Int
forall (e :: Effect) (es :: [Effect]). (e :> es) => Int
reifyIndex @e @es
type ElemNotFound e = Text "The element '" :<>: ShowType e :<>: Text "' is not present in the constraint"
instance TypeError (ElemNotFound e) => e :> '[] where
reifyIndex :: Int
reifyIndex = String -> Int
forall a. HasCallStack => String -> a
error
String
"Cleff.Internal.Stack.reifyIndex: Attempting to refer to a nonexistent member. Please report this as a bug."
type family xs :>> es :: Constraint where
'[] :>> _ = ()
(x : xs) :>> es = (x :> es, xs :>> es)
infix 0 :>>
index :: ∀ e es. e :> es => Stack es -> HandlerPtr e
index :: Stack es -> HandlerPtr e
index = (Int -> PrimVec Int -> Int) -> Int -> Stack es -> HandlerPtr e
coerce (Prim Int => Int -> PrimVec Int -> Int
forall a. Prim a => Int -> PrimVec a -> a
Vec.index @Int) ((e :> es) => Int
forall (e :: Effect) (es :: [Effect]). (e :> es) => Int
reifyIndex @e @es)
class KnownList es => Subset (es :: [Effect]) (es' :: [Effect]) where
reifyIndices :: [Int]
reifyIndices = String -> String -> String -> [Int]
forall a. String -> String -> String -> a
unreifiable
String
"Subset" String
"Cleff.Internal.Stack.reifyIndices" String
"the indices of a subset of the effect stack"
instance Subset '[] es where
reifyIndices :: [Int]
reifyIndices = []
instance (Subset es es', e :> es') => Subset (e : es) es' where
reifyIndices :: [Int]
reifyIndices = (e :> es') => Int
forall (e :: Effect) (es :: [Effect]). (e :> es) => Int
reifyIndex @e @es' Int -> [Int] -> [Int]
forall a. a -> [a] -> [a]
: Subset es es' => [Int]
forall (es :: [Effect]) (es' :: [Effect]). Subset es es' => [Int]
reifyIndices @es @es'
pick :: ∀ es es'. Subset es es' => Stack es' -> Stack es
pick :: Stack es' -> Stack es
pick = (Int -> [Int] -> PrimVec Int -> PrimVec Int)
-> Int -> [Int] -> Stack es' -> Stack es
coerce (Prim Int => Int -> [Int] -> PrimVec Int -> PrimVec Int
forall a. Prim a => Int -> [Int] -> PrimVec a -> PrimVec a
Vec.pick @Int) (KnownList es => Int
forall (es :: [Effect]). KnownList es => Int
reifyLen @es) (Subset es es' => [Int]
forall (es :: [Effect]) (es' :: [Effect]). Subset es es' => [Int]
reifyIndices @es @es')
update :: ∀ e es. e :> es => HandlerPtr e -> Stack es -> Stack es
update :: HandlerPtr e -> Stack es -> Stack es
update = (Int -> Int -> PrimVec Int -> PrimVec Int)
-> Int -> HandlerPtr e -> Stack es -> Stack es
coerce (Prim Int => Int -> Int -> PrimVec Int -> PrimVec Int
forall a. Prim a => Int -> a -> PrimVec a -> PrimVec a
Vec.update @Int) ((e :> es) => Int
forall (e :: Effect) (es :: [Effect]). (e :> es) => Int
reifyIndex @e @es)