Using a variant to update a single label in a record

I’ve got an interesting problem to solve, perhaps with heterogeneous, perhaps in another type-safe way, perhaps in an unsafe way. The reason I might reach for unsafe is because I’m trying to leverage fewer constraints in my library to aid compile times.

The problem

I have a variant that contains a set of labels and values. I have a record that contains the identical set of labels and values that, while not identical to the types of the variant values, are compatible with them – you can use the variant’s value to construct the record’s value for each pair of labels.

My goal is to take a variant and modify the record at the same label so that the record’s value is modified using the variant’s value.

I already have a RowCons boilerplate class written for this, and I know it’s possible to write something in heterogeneous to do this with successive ons chained together.

But it seems more efficient for me to simply take the variant’s label and value and use that information to modify the record directly rather than iterate through the entire record searching for the case that matches.

Anyone have a suggested approach to solve this?


Variant:                                Record:
( foo :: InputField Error i Output ) -> ( foo :: FormField Error i Output )
  ex: foo = InputField "boo"              ex: foo = FormField { (input :: i): "boo", ... }

- All labels are identical in both rows.
- The type of `i` is the same in both rows (in this case, String)
- The variant's value should replace the `input` field in the record's value for the same label


  1. Use unsafeCoerce to VariantRep to retrieve the label and value from the variant, and then use that to modify the record at the same label (perhaps with unsafeModify). I’m confident that the labels in the record and variant are identical because I generate both from the same underlying row (Variant row vs. Record row)

  2. Attempt to do the same thing, but with some fancy constraints that prove that the same labels exist in both rows without being forced to iterate / pattern match through the whole record

  3. Give up on just using the variant directly, and chain on statements together either with heterogeneous or a RowCons boilerplate class