
On 23/02/16 22:07, Daniel Díaz wrote:
I was wondering: if I define a bunch of records in a module, how to make this the behaviour for all records in the module, without much boilerplate and without affecting any records elsewhere?
One possible solution would be to define a empty type class that will not be exported:
class Marker r
and the following instance:
instance (Marker r,IsLabel symbol (r -> String)) => IsLabel symbol (r -> Text) where fromLabel _ = Text . fromLabel (proxy# :: (Proxy# symbol))
Unfortunately this will overlap with any fields defined elsewhere that return Text, which is perhaps not ideal.
And make every record in the module an instance of Marker:
instance Marker Person
I'm not sure if there's a simpler way.
I think ultimately we want to pick a single IsLabel instance for the function space, to be defined in base. That will create a standard way to use overloaded labels with records. This is discussed a bit on the wiki [1]. Probably the instance should delegate to another class that captures which fields belong to which records. Unfortunately there are some design trade-offs, so it's not entirely clear what this instance should look like. The plan is to experiment with the options in 8.0 and try to commit to something in a future GHC release.
Even if we don't export the fields directly, another way to employ OverloadedLabels (OverloadedRecordFields, once it arrives) is for giving default implementations of public interfaces, in combination with DefaultSignatures. A not very useful example:
class Named r where name :: r -> String default name :: IsLabel "name" (r -> String) => r -> String name = #name
instance Named Person
Thanks, this is an interesting use case that hadn't occurred to me. All the best, Adam [1] https://ghc.haskell.org/trac/ghc/wiki/Records/OverloadedRecordFields/MagicCl... -- Adam Gundry, Haskell Consultant Well-Typed LLP, http://www.well-typed.com/