How would I go about deriving the function
getField :: (Generic a, HasDatatypeInfo a) => Proxy (name :: Symbol) -> a -> b
to project a field from an arbitrary record using a type-level string (Symbol
), using the generics-sop
library?
This is similar to Retrieving record function in generic SOP, but I have the following problems:
DataTypeInfo
is provided through the DatatypeInfoOf
type family (nice to have, but not necessary).The lens-sop
package also seems to do something similar, but I can't work out how to make it work for me.
I would also prefer a solution that uses the IsProductType
typeclass.
As of version 0.1.1.0, records-sop
provides this function:
getField :: forall s a b ra. (IsRecord a ra, IsElemOf s b ra) => a -> b
which needs the field name supplied as a type application rather than a proxy, like so:
data Foo = Foo { bar :: Int }
getField @"bar" (Foo 42) === 42
This provides compile-time extraction, although it will still need a bit of casting around to fit in with existing code in my project that manipulates standard generics-sop
metadata.
This only works on single-constructor types. @dfeuer's answer also supports sum types.
Thank you @kosmikus, the coauthor of generics-sop
and author of records-sop
, for implementing this in response to this question!