You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The gist of this proposal is to swap the Proxy idx type out in this library
for a new type (1):
--| An int between 0 (inclusive) and bound (exclusive)newtypeIndex :: Int->TypenewtypeIndexbound=IndexInttyperoleIndexnominal
With the breaking changes involved in switching to VTA already in #27, now seems like a great opportunity to consider other breaking changes against the core api.
Nice things that fall out of this:
Type-safe indices into an array can be parsed at runtime
Index objects can be safely manipulated at runtime while retaining access guarantees
Can fully re-use standard numeric typeclasses on indices
Downsides:
Code migration potentially gets a bit harder for existing users
Index might not be able to be erased as aggressively by the compiler/jit, but the new type-application
based methods introduced in Switch to visible type applications #27 should be a significant mitigation
Full implementation I've been tooling around with
moduleData.FastVect.Index (Index, reflectInt, index, (!!), widen, parse, modulo) whereimportPreludeimportControl.Monad.STasSTimportData.Array.STasArraySTimportData.Array.ST.PartialasArraySTPartialimportData.Enum (classBoundedEnum, classEnum, Cardinality(..), toEnum)
importData.FastVect.FastVect (Vect)
importData.FastVect.FastVectasFastVectimportData.Maybe (Maybe(..))
importData.Reflectable (classReflectable, reflectType)
importPartial.Unsafe (unsafeCrashWith, unsafePartial)
importPreludeasPreludeimportPrim.Int (classAdd, classCompare)
importPrim.Ordering (GT, LT)
importPrim.TypeErrorasTypeErrorimportSafe.Coerce (coerce)
importType.Prelude (Proxy(..))
--| An int between 0 (inclusive) and bound (exclusive)newtypeIndex :: Int->TypenewtypeIndexbound=IndexInttyperoleIndexnominalderive newtype instanceEq (Indexbound)
derive newtype instanceOrd (Indexbound)
instanceReflectableboundInt=>Show (Indexbound) where
show (Index idx) =
"Index " <> show idx <> " within bound: " <> show (reflectType (Proxy @bound))
infixr2 type TypeError.Beside as <>
infixr1 type TypeError.Above as |>
typeZeroErrorMsg :: Symbol->Symbol->TypeError.DoctypeZeroErrorMsgclassNameclosing=TypeError.Text "Cannotcreate " <> TypeError.QuoteLabelclassName
<> TypeError.Text " instancefor " <> TypeError.Quote (Index 0)
|> TypeError.Text "Acollectionofsize 0 hasnoelementstoindexinto; "
<> TypeError.Text "equivalently, thetype " <> TypeError.Quote (Index 0)
<> TypeError.Text "isuninhabited (i.e. cannotbeinstantiatedlike " <> TypeError.QuotePrelude.Void
<> TypeError.Text ")."
<> TypeError.TextclosinginstancesemiringIndexZeroError ::
TypeError.Fail (ZeroErrorMsg"Semiring""As such, the `one` and `zero` type class members cannot exist")
=> Semiring (Index0) where
zero = unsafeCrashWith "absurd"
one = unsafeCrashWith "absurd"
add _ _ = unsafeCrashWith "absurd"
mul _ _ = unsafeCrashWith "absurd"else instancesemiringIndexDegenerate :: Semiring (Index 1) where
zero = Index0
one = Index0
add _ _ = zero
mul _ _ = zero
else instancesemiringIndexGt1 :: (Comparebound 1 GT, ReflectableboundInt) =>Semiring (Index bound) where
zero = Index0
one = Index1
add (Index a) (Index b) = (Index $ (a + b) `mod` (reflectType (Proxy @bound)))
mul (Index a) (Index b) = (Index $ (a * b) `mod` (reflectType (Proxy @bound)))
instance (Comparebound 0 GT, ReflectableboundInt) =>Bounded (Indexbound) where
top = Index $ (reflectType $ Proxy @bound) - 1
bottom = Index0instance (Comparebound 0 GT, ReflectableboundInt) =>Enum (Indexbound) where
succ (Index idx) =
if idx < (reflectType $ Proxy @bound) - 1thenJust (Index $ idx + 1)
elseNothing
pred (Index idx) =
if idx > 0thenJust (Index $ idx - 1)
elseNothinginstance (Comparebound 0 GT, ReflectableboundInt) =>BoundedEnum (Indexbound) where
cardinality = Cardinality0
toEnum int =
if0 <= int && int < (reflectType $ Proxy @bound) thenJust (Index int)
elseNothing
fromEnum (Index int) = int
parse::forall (@bound::Int).
Comparebound 0 GT=>ReflectableboundInt=>Int->Maybe (Indexbound)
parse = toEnum @(Index bound)
modulo::forall (@bound::Int).
Comparebound 1 GT=>ReflectableboundInt=>Int->Indexbound
modulo idx = Index (idx `mod` (reflectType $ Proxy @bound))
--| Reflect a type-level integer into a valid Index--| Note: with how `at` is implemented, the created `Index`--| is valid for any `Vect n a` where `@int < n`reflectInt::forall (@int::Int) (bound::Int).
ReflectableintInt=>Compareint (-1) GT=>Addint 1 bound=>Indexbound
reflectInt = Index (reflectType (Proxy @int))
widen::forall (@widenedBound::Int) (currentBound::Int) (currentBoundMinusOne::Int).
AddcurrentBound (-1) currentBoundMinusOne=>ComparewidenedBoundcurrentBoundMinusOneGT=>IndexcurrentBound->IndexwidenedBound
widen = coerce
index::forall (idxBound::Int) (vectSize::Int) (idxBoundMinusOne::Int) a.
CompareidxBound 0 GT=>ComparevectSize 0 GT=>AddidxBound (-1) idxBoundMinusOne=>CompareidxBoundMinusOnevectSizeLT=>IndexidxBound->VectvectSizea->a
index (Index idx) vec =
ST.run
(ArrayST.unsafeThaw (FastVect.toArray vec)
>>= (unsafePartial ArraySTPartial.peek idx))
infixl8 index as !!
(1): Not very attached to the name Index, nor any of the names in my code, for that matter
The text was updated successfully, but these errors were encountered:
thanks! Looks very interesting. The idea of the VTAs is to get rid of the Proxy alltogether, but I can see the advantage of your proposal. I think if we add this, it would make sense to have that as a separate functionality, like index' or something like this. Let me get the VTA PR through first and then we can have a PR and see how that works out, what do you think?
The gist of this proposal is to swap the
Proxy idx
type out in this libraryfor a new type (1):
With the breaking changes involved in switching to VTA already in #27, now seems like a great opportunity to consider other breaking changes against the core api.
Nice things that fall out of this:
Downsides:
Index
might not be able to be erased as aggressively by the compiler/jit, but the new type-applicationbased methods introduced in Switch to visible type applications #27 should be a significant mitigation
Full implementation I've been tooling around with
(1): Not very attached to the name
Index
, nor any of the names in my code, for that matterThe text was updated successfully, but these errors were encountered: