Skip to content

Instantly share code, notes, and snippets.

@natefaubion
Created March 29, 2024 17:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save natefaubion/fd4da5240adedf599c811c6f67bd0053 to your computer and use it in GitHub Desktop.
Save natefaubion/fd4da5240adedf599c811c6f67bd0053 to your computer and use it in GitHub Desktop.
Record merge with evidence
// @inline export mergeRecord arity=7
// @inline export mergeRecordRhsSkip arity=1
// @inline export mergeRecordRhsCons arity=5
// @inline export mergeRecordRhsNil always
const mergeRecord = () => () => () => () => () => () => dictMergeRecordRhs => ({merge: a => b => dictMergeRecordRhs.mergeRecordRhs(a)(b)});
const merge = dict => dict.merge;
const test1 = {bar: false, foo: 12};
const test2 = v => ({...v, bar: false});
const test3 = v => ({bar: v.bar, foo: 12});
export {merge, mergeRecord, test1, test2, test3};
-- @inline export mergeRecord arity=7
-- @inline export mergeRecordRhsSkip arity=1
-- @inline export mergeRecordRhsCons arity=5
-- @inline export mergeRecordRhsNil always
module RecordMerge
( class Merge
, merge
, test1
, test2
, test3
) where
import Data.Symbol (class IsSymbol)
import Prim.Row as Row
import Prim.RowList (class RowToList, Cons, Nil, RowList)
import Record as Record
import Type.Proxy (Proxy(..))
class Merge a b c | a b -> c where
merge :: a -> b -> c
instance mergeRecord ::
( Row.Nub r1 r1n
, Row.Nub r2 r2n
, RowToList r1n r1l
, MergeRecordLhs r1l r2n r2d
, Row.Nub r2d r2dn
, RowToList r2dn r2dnl
, MergeRecordRhs r2dnl r1n r2n r3
) =>
Merge { | r1 } { | r2 } { | r3 } where
merge a b = mergeRecordRhs @r2dnl (Record.nub a) (Record.nub b)
class MergeRecordLhs :: RowList Type -> Row Type -> Row Type -> Constraint
class MergeRecordLhs rl r1 r2 | rl r1 -> r2
data Deleted
instance
( Row.Cons sym Deleted r1 r3
, MergeRecordLhs rl r2 r3
) =>
MergeRecordLhs (Cons sym a rl) r1 r3
instance MergeRecordLhs Nil r1 r1
class MergeRecordRhs :: RowList Type -> Row Type -> Row Type -> Row Type -> Constraint
class MergeRecordRhs rl r1 r2 r3 | rl r1 r2 -> r3 where
mergeRecordRhs :: { | r1 } -> { | r2 } -> { | r3 }
instance mergeRecordRhsSkip ::
( MergeRecordRhs rl r1 r2 r3
) =>
MergeRecordRhs (Cons sym Deleted rl) r1 r2 r3 where
mergeRecordRhs = mergeRecordRhs @rl
else instance mergeRecordRhsCons ::
( IsSymbol sym
, MergeRecordRhs rl r1 r2 r3'
, Row.Lacks sym r3'
, Row.Cons sym a r3' r3
, Row.Cons sym a rx r2
) =>
MergeRecordRhs (Cons sym a rl) r1 r2 r3 where
mergeRecordRhs a b = Record.insert (Proxy :: _ sym) (Record.get (Proxy :: _ sym) b) (mergeRecordRhs @rl a b)
instance mergeRecordRhsNil :: MergeRecordRhs Nil r1 r2 r1 where
mergeRecordRhs a _ = a
test1 = merge { foo: 12 } { foo: "hello", bar: false }
test2 (a :: { foo :: Int }) = merge a { foo: "hello", bar: false }
test3 (b :: { foo :: String, bar :: Boolean }) = merge { foo: 12 } b
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment