Legend:

Any module that imports `M` will have access to the `x` field from `R` but not from `S`, because the instance `Has R "x" Int` will be in scope but the instance `Has S "x" Bool` will not be. Thus `R { x :: Int }` will be solved but `S { x :: Bool }` will not.

82

83

84

=== Record selectors ===

85

86

Optionally, we could [wiki:Records/DeclaredOverloadedRecordFields/NoMonoRecordFields add a flag `-XNoMonoRecordFields`] to disable the generation of the usual monomorphic record field selector functions. This is not essential, but would free up the namespace for other record systems (e.g. '''lens'''). Note that `-XOverloadedRecordFields` will generate monomorphic selectors by default for backwards compatibility reasons, but they will not be usable if multiple selectors with the same name are in scope.

87

88

When either flag is enabled, the same field label may be declared repeatedly in a single module (or a label may be declared when a function of that name is already in scope).

89

90

Even if the selector functions are suppressed, we still need to be able to mention the fields in import and export lists, to control access to them (as discussed in the previous section).

91

92

'''AMG''' perhaps we should also have a flag to automatically generate the polymorphic record selectors? These are slightly odd: if two independent imported modules declare fields with the same label, only a single polymorphic record selector should be brought into scope.

Optionally, we could [wiki:Records/DeclaredOverloadedRecordFields/NoMonoRecordFields add a flag `-XNoMonoRecordFields`] to disable the generation of the usual monomorphic record field selector functions. This is not essential, but would free up the namespace for other record systems (e.g. '''lens'''). Note that `-XOverloadedRecordFields` will generate monomorphic selectors by default for backwards compatibility reasons, but they will not be usable if multiple selectors with the same name are in scope.

151

152

When either flag is enabled, the same field label may be declared repeatedly in a single module (or a label may be declared when a function of that name is already in scope).

153

154

Even if the selector functions are suppressed, we still need to be able to mention the fields in import and export lists, to control access to them (as discussed in the [wiki:Records/OverloadedRecordFields/Plan#Representationhiding representation hiding] section).

155

156

'''AMG''' perhaps we should also have a flag to automatically generate the polymorphic record selectors? These are slightly odd: if two independent imported modules declare fields with the same label, only a single polymorphic record selector should be brought into scope.

'''SLPJ''' Making the first example rely on the monomorphism restriction is not a good plan!

178

=== Higher-rank fields ===

179

180

If a field has a rank-1 type, the `Has` encoding works fine: for example,

181

{{{

182

data T = MkT { x :: forall a . a -> a }

183

}}}

184

gives rise to the instance

185

{{{

186

instance b ~ a -> a => Has T "x" b

187

}}}

188

189

However, if a field has a rank-2 type or higher (so the selector function has rank at least 3), things are looking dangerously impredicative:

190

{{{

191

data T b = MkT { x :: (forall a . a -> a) -> b }

192

}}}

193

would give

194

{{{

195

instance c ~ (forall a . a -> a) -> b => Has (T b) "x" c

196

}}}

197

but this is currently forbidden by GHC, even with `-XImpredicativeTypes` enabled. Indeed, it would not be much use if it were possible, because bidirectional type inference relies on being able to immediately infer the type of neutral terms like `e.x`, but overloaded record fields prevent this. Traditional monomorphic selector functions are likely to be needed in this case.

When checking `qux`, the projection has type `alpha -> beta` and generates the constraint `alpha { y :: beta }`. However, the monomorphism restriction prevents this constraint from being generalised. There is only one `y` field in scope, so defaulting specialises the type to `S -> Bool`. If the `x` field was used, it would instead give rise to an ambiguity error.