large-records-0.1.0.0: Efficient compilation for large records, linear in the size of the record
Safe HaskellNone
LanguageHaskell2010

Data.Record.Internal.Record.Resolution

Synopsis

Documentation

resolveRecord Source #

Arguments

:: Quasi m 
=> String

User-defined constructor

-> Name 'DataName 'Global

Internal constructor

-> m (Either String (Record ())) 

Resolve record info

When the quasi-quoter needs to turn

[lr| MkRecord { field2 = 5, field1 = True } |]

into

_construct_MkRecord True 5

it needs to know the record definition: the types of all fields, and the order of all fields.

The primary means through which we achieve this is by looking up the MetadataOf type family instance for the record, and then parsing that (parseRecordInfo).

Unfortunately, however, this does not always work. In an example such as

largeRecord defaultPureScript [d|
    data SomeRecord = MkRecord { field1 :: Int, field2 :: Bool }
  |]

foo :: SomeRecord
foo = [lr| MkRecord { field1 = 5, field2 = True } |]

the call to largeRecord and the definition of foo is considered to be a single binding group (not entirely sure why). Both the largeRecord splice and the lr quasi-quote are now run before typechecking, which is why when we get to the lr quasi-quote, the MetadataOf instance is not yet available, even though it has been generated.

One work-around is to insert an empty splice

largeRecord defaultPureScript [d|
    data SomeRecord = MkRecord { field1 :: Int, .. }
  |]

$(return [])

foo :: SomeRecord
foo = [lr| MkRecord { field1 = 5, .. } |]

That works (and we previously did that, giving that empty splice a name endOfBindingGroup), but requiring this is bad for useability of the lib. Most users probably don't know what binding groups even are, much less want to think about the scope of each binding group: that's a task for ghc.

Therefore, in addition to being able to parse the MetadataOf instance, we also maintain our own environment, mapping constructor names to record info (see getRecordInfo). The largeRecord splice adds entries into this environment, and the lr quasi-quoter consults this environment. The contents of this environment are ephemeral, of course, and certainly not stored as part of interface files, so this is merely a backup for when the MetadataOf information is not available.