Hi! I’m not sure the title is very clear, but here’s a better explanation.
I want to build a function that allows to build a Aff.Request String
overriding fields of the defaultRequest
.
For example:
buildRequest { url, method }
Asking on slack, I was suggested to use this class to get the row out of a record:
class RecordRow (t :: Type) (r :: # Type) | t -> r
instance recordRowInst :: RecordRow (Record r) r
else
instance recordRowFail :: Fail (Beside (Text "RecordRow applied to non record type: ") (Quote t)) => RecordRow t r
I added it to this function:
buildRequest ::
forall r s t x.
RecordRow (Request String) s =>
Row.Nub t s =>
Row.Union r s t =>
Row.Union r x s =>
{ | r } ->
Request String
buildRequest r = Record.merge r defaultSimpleRequest
The compiler complains that there’s a missing instance for Union r x t
, where x
is Request String
's row.
I must be doing something wrong, but I’m not sure what
I think you want
buildRequest ::
forall rsub rall rx.
RecordRow (Request String) rall =>
Row.Union rsub rall rx =>
Row.Nub rx rall =>
{ | r } ->
Request String
That is you want to merge the fields of rsub and rall, and then assert that the nubbed labels are equivalent to rall.
I get the same error. I tried some variations (not sure if you meant r
and rsub
to be different, tried Record.union
instead of Record.merge
), but the problem is still that the compiler doesn’t seem to understand that rall
corresponds to the row of Request String
.
My solution works when I can explicitly pass { | rall }
instead of Request String
, but it’s not what I need.
The type system doesn’t automatically propagate equivalences like that, so you’d have to add some evidence to your class.
defaults ::
forall rall rsub rx.
Row.Union rsub rall rx =>
Row.Nub rx rall =>
{ | rall } ->
{ | rsub } ->
{ | rall }
defaults = flip Record.merge
type Request a =
{ foo :: a
, bar :: Int
}
class RecordRows a (r :: # Type) | a -> r where
toRows :: a -> { | r }
instance recordRows :: RecordRows { | r } r where
toRows = identity
buildRequest ::
forall r rall rx.
RecordRows (Request String) rall =>
Row.Union r rall rx =>
Row.Nub rx rall =>
{ | r } ->
{ | rall }
buildRequest = defaults $ toRows { foo: "", bar: 42 }
If at all possible, the easiest thing is to just have a synonym of of the rows in Request
so you can avoid the class. I know you probably want to use the same synonym from whatever library, but I would just define my own to avoid this nastiness.
I see, I assumed that having the constraint was enough. This is the problem of learning by just copying and and trying to do stuff without undestanding it
This solution works great btw. Why do you call it nasty? I feel it’s less elegant and clear to copy and paste Request
's rows manually, but maybe I’m missing something obvious.
Thanks again for your help!
Because I find it annoying to have to deal with equivalence coercions.