@@ -222,18 +222,23 @@ type family KeyDoesNotExist (l :: Symbol) (lts :: [*]) :: Constraint where
222222 )
223223 KeyDoesNotExist q (l := t ': lts) = KeyDoesNotExist q lts
224224
225+type family Reverse (xs :: [*]) where
226+ Reverse '[] = '[]
227+ Reverse (x ': xs) = RecAppend (Reverse xs) '[x]
228+
225229type family Insert (a :: *) (xs :: [*]) where
226− Insert (a := t) '[] = a := t ': '[]
227− Insert (a := t1) (a := t2 ': xs) = a := t1 ': xs
228− Insert (a := t1) (x := t2 ': xs) = x := t2 ': Insert (a := t1) xs
230+ Insert x '[] = x ': '[]
231+ Insert (a := v) (a := _ ': xs) = a := v ': xs
232+ Insert a (x ': xs) = x ': Insert a xs
229233
230234type family Union xs ys where
231235 Union xs '[] = xs
232236 Union xs (y := t ': ys) = Union (Insert (y := t) xs) ys
233237
238+-- TODO: Rename to `Append`, because it just deals with general type list?
234239type family RecAppend lhs rhs where
235240 RecAppend '[] rhs = rhs
236− RecAppend (x := t ': xs) rhs = x := t ': RecAppend xs rhs
241+ RecAppend (x ': xs) rhs = x ': RecAppend xs rhs
237242
238243type family RecSize (lts :: [*]) :: Nat where
239244 RecSize '[] = 0
@@ -394,9 +399,7 @@ combine lts rts =
394399 (# s''''#, a# #) -> (# s''''#, MkRec a# #)
395400{-# INLINE combine #-}
396401
397−-- | Union two records
398−--
399−-- NOTE: changed from original superrecord to not require a 'Sort'
402+-- | Union two records (left-biased)
400403union ::
401404 forall lhs rhs res.
402405 ( KnownNat (RecSize lhs),
@@ -426,6 +429,37 @@ union lts rts =
426429 (# s''''#, a# #) -> (# s''''#, MkRec a# #)
427430{-# INLINE union #-}
428431
432+-- | Insert a field
433+--
434+-- Insert at beginning, unless the field already exists, in which case set it
435+-- directly.
436+insert ::
437+ forall l v rhs res.
438+ ( KnownNat (RecSize rhs),
439+ KnownNat (RecSize res),
440+ res ~ Reverse (Insert (l := v) (Reverse rhs)),
441+ RecCopy '[l := v] '[l := v] res,
442+ RecCopy rhs rhs res
443+ ) =>
444+ l := v ->
445+ Rec rhs ->
446+ Rec res
447+insert (l := v) rts =
448+ let !(I# size#) =
449+ fromIntegral $ natVal' (proxy# :: Proxy# (RecSize res))
450+ in runST' $
451+ ST $ \s# ->
452+ case newSmallArray# size# (error "No value") s# of
453+ (# s'#, arr# #) ->
454+ case recCopyInto (Proxy :: Proxy rhs) rts (Proxy :: Proxy res) arr# s'# of
455+ s''# ->
456+ case recCopyInto (Proxy :: Proxy '[l := v]) (unsafeRCons (l := v) $ unsafeRNil 1) (Proxy :: Proxy res) arr# s''# of
457+ s'''# ->
458+ case unsafeFreezeSmallArray# arr# s'''# of
459+ (# s''''#, a# #) -> (# s''''#, MkRec a# #)
460+{-# INLINE insert #-}
461+
462+
429463
430464-- | Alias for 'combine'
431465(++:) ::