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
Right now, a Variant only permits a single value to be associated with a tag:
newtypeVariantRepa=VariantRep{type::String
, value::a}foreignimportdataVariant:: Row Type -> Type
dataOneOrPair0=OneInt
| PairIntInttypeOneOrPair1=Variant
( one :: Int
, pair :: TupleIntInt
)
If one wants to define a Variant-based List type, they pay for an extra level of boxing:
newtypeLista=List (
Variant
( nil :: Unit-- extra nesting occurs here due to usage of -- `Tuple` to store 2 args
, cons :: Tuplea (Lista)
)
)
_nil = Proxy :: Proxy"nil"
_cons = Proxy :: Proxy"cons"
nil = List $ V.inj _nil unit
cons head tail = List $ V.inj cons_ $ Tuple head tail
cons12 = cons 1 $ cons 2 nil
{-which has the following runtime representation on JS:{ type: "cons", value: { tag: "Tuple" -- extra nesting , value0: 1 , value1: { type: "cons" , value: { tag: "Tuple" -- extra nesting , value0: 2 , value1: { type: "nil" , value: undefined } } } }}-}
AFAICT, Variant could denest this extra boxing by using the following representation, which I call Variance to distinguish it from the current Variant. I show both Variant and Variance below to show the small change made:
inj
::forallsymctorRowsctorsTailctorsAll
. Row.Lacks "__ctorTag" ctorRows=>Row.ConssymctorRowsctorsTailctorsAll=>IsSymbolsym=>Proxysym-> { | ctorRows }
->VariancectorsAll
inj p value = coerceV $ VarianceRep $ Record.insert __ctorTag (reflectSymbol p) value
wherecoerceV::VarianceRepctorRows→VariancectorsAll
coerceV = unsafeCoerce
Similarly, Variance.on is implemented as below. Notably, the entire representation is passed to the function so as not to duplicate the record without the __ctorTag field:
on
::forallsymctorRowsremainingallb
. Row.ConssymctorRowsremainingall=>ReflectablesymString=>Proxysym-> ({ __ctorTag :: String | ctorRows } ->b)
-> (Varianceremaining->b)
->Varianceall->b
on p f g r = case coerceR r ofVarianceRep rep | rep.__tag == reflectSymbol p -> f rep
_ -> g (coerceTail r)
wherecoerceR::Varianceall->VarianceRepctorRows
coerceR = unsafeCoerce
coerceTail::Varianceall->Varianceremaining
coerceTail = unsafeCoerce
By using the above representation, it enables the following Variance-based List type:
Besides the smaller boxing, the Nil case also doesn't specify an unused value as it's runtime representation is just { __ctorTag: "nil" }. If one wanted to remove even that boxing and just have the string "Nil" for constructors that have no arguments, then FFI would need to be added that does a typeof x === "string" check.
The text was updated successfully, but these errors were encountered:
Right now, a
Variant
only permits a single value to be associated with a tag:If one wants to define a
Variant
-basedList
type, they pay for an extra level of boxing:as opposed to just using
List
directly:AFAICT,
Variant
could denest this extra boxing by using the following representation, which I callVariance
to distinguish it from the currentVariant
. I show bothVariant
andVariance
below to show the small change made:Variance.inj
is implemented as:Similarly,
Variance.on
is implemented as below. Notably, the entire representation is passed to the function so as not to duplicate the record without the__ctorTag
field:By using the above representation, it enables the following
Variance
-basedList
type:Besides the smaller boxing, the
Nil
case also doesn't specify an unusedvalue
as it's runtime representation is just{ __ctorTag: "nil" }
. If one wanted to remove even that boxing and just have the string"Nil"
for constructors that have no arguments, then FFI would need to be added that does atypeof x === "string"
check.The text was updated successfully, but these errors were encountered: