natefaubion/purescript-variant

Construct a variant from a record

joneshf opened this issue · 3 comments

Is there any interest in adding something that allows constructing a variant with a singleton record?

foo :: Data.Variant.Variant (bar :: Int, baz :: String, qux :: Boolean)
foo = Data.Variant.fromRecord { qux: true }

The motivation here is that using SProxy _ is a bit more cumbersome than seems necessary. Record syntax is a bit more lightweight to toss around.

It seems like fromRecord could be implemented like:

module Data.Variant where

class FromRecord (list :: Prim.RowList.RowList) record variant where
  fromRecord' :: forall proxy. proxy list -> Record record -> Variant variant

instance fromRecordSingleton ::
  ( Data.Symbol.IsSymbol label
  , Prim.Row.Cons label value () record
  , Prim.Row.Cons label value variant' variant
  ) =>
  FromRecord (Prim.RowList.Cons label value Prim.RowList.Nil) record variant
    where
      fromRecord' _ record = inj label (Record.get label record)
        where
        label :: Data.Symbol.SProxy label
        label = Data.Symbol.SProxy

fromRecord ::
  forall list record variant.
  Prim.RowList.RowToList record list =>
  FromRecord list record variant =>
  Record record ->
  Variant variant
fromRecord = fromRecord' (Type.Data.RowList.RLProxy :: _ list)

Might want some fundeps, dunno. If we want to be helpful, adding some custom error messages for using the wrong size record should be possible as well:

else instance fromRecordMultiple ::
  ( Prim.TypeError.Fail ?someErrorMessageAboutMultipleFieldsInTheRecord
  ) =>
  FromRecord (Prim.RowList.Cons label value list) record variant
    where
      fromRecord' proxy record = fromRecord' proxy record
else instance fromRecordEmpty ::
  ( Prim.TypeError.Fail ?someErrorMessageAboutTheEmptyRecord
  ) =>
  FromRecord Prim.RowList.Nil record variant
    where
      fromRecord' proxy record = fromRecord' proxy record

Looks great!

Maybe as name use injRecord or injR so it's closer to current vocabulary

here you go #44