I'm writing an extensible records library for fun and profit. I have two potential 'Monoid' instances I can give my 'HashRecord' type. Which would you prefer to see?
The record type is essentially HashRecord f xs
, where xs
is a type level list of (key :: Symbol) =: (value :: *)
pairs, and f
is a type constructor that each entry in the record is contained in.
mempty does pure mempty
for each field in the record, and mappend
does liftA2 mappend
for the fields in the record.
>>> mempty :: HashRecord' Identity ["foo" =: String, "bar" =: Any]
fromList [("foo", "\"\""), ("bar", "Any { getAny = False }")]
instance Monoid (HashRecord' f '[]) where
mempty = HashRecord mempty
mappend a _ = a -- empty + empty = empty
instance
( Monoid val
, Applicative f
, MapEntry key val
, Monoid (HashRecord' f xs)
) => Monoid (HashRecord' f (key =: val ': xs)) where
mempty = -- insert key (pure mempty) (mempty :: HashRecord' f xs)
mappend = -- Map.unionWith (liftA2 mappend)
mempty
returns Alternative.empty
for each entry in the field, and mappend
does <|>
over each entry.
>>> mempty :: HashRecord' Maybe ["foo" =: Int, "bar" =: Bool]
fromList [("foo", "Nothing"), ("bar", "Nothing")]
instance Monoid (HashRecord' f '[]) where
mempty = HashRecord mempty
mappend a _ = a -- empty + empty = empty
instance
( Alternative f
, MapEntry key val
, Monoid (HashRecord' f xs)
) => Monoid (HashRecord (key =: val ': xs)) where
mempty = -- insert key Alternative.empty (mempty :: HashRecord xs)
mappend = -- Map.unionWith (<|>)