Get row from record type alias

I am using the Union class but am having a problem using my record type aliases because Union uses # Type but my aliases are Type.

type PageQuery q =
  { pageSize :: Int
  , pageIndex :: Int
  | q }

  :: forall m q r a
   . MonadAff m
  => MonadThrow String m
  => EncodeJson (PageQuery q)
  => DecodeJson (PageResponse a)
  => DecodeJson r
  => Union q (pageIndex :: Int , pageSize :: Int) (pageIndex :: Int , pageSize :: Int | q)
  => URL -> Record q -> m (Array a)
getAllItems u q = evalStateT
  (unfoldM (getItem :: StateT (Page q r a) m (Maybe a))) $
  Page {url: u, query: union q defautlPageQuery :: PageQuery q} Nothing

It would be nice to be able to reference the type alias PageQuery instead of having to use the row names in the line

  => Union q (pageIndex :: Int , pageSize :: Int) (pageIndex :: Int , pageSize :: Int | q)

Is there a class like class RecordRow (a :: Record (# Type)) (b :: # Type)?

Why not provide another alias?

type PageQueryRows r = ( pageSize :: Int, pageIndex :: Int | r)
type PageQuery q = { | PageQueryRows q }

Seems like you have thought about this before.

1 Like

I still wish there was a way to get a row type from a record type.

For example we can get a record from a row:

type MyRow = ( foo :: Int, bar :: Number )
type MyRecord = Record MyRow

Why can’t we go the other way?:

type MyRecord = { foo :: Int, bar :: Number }
type MyRow = Row MyRecord -- `Row` does not exist yet

I seems like the compiler should have also the info it needs to figure this out.

I usually start by writing records, and then eventually need to apply the workaround that Jordan recommends, which involves rewriting my records as rows. It would be more ergonomic if I could just keep the original record definition and get the row from that.

1 Like

@milesfrain I do agree. I now have Record (PageQuery q) scattered throughout my code instead of Row (PageQuery q) in one place.

If we had a Row type constructor like that which takes us from records to rows, that would essentially entail supporting type families. Type families make lots of things (such as other type system features) much more complicated, and in my view do not offer a good enough “power-to-weight” ratio to justify supporting them. The Thoughts on future additions of type-level features thread has further discussion on this.

For example, at the moment, if you’re comparing a type of the form f a to a type of the form B, where f and a are type variables but B is a concrete type, then at the moment you have enough information to conclude that the types don’t match. In the presence of type families, you can no longer come to that conclusion, because f might be a type family which evaluates to B when applied to a.