Context
If we have
data Foo = Foo { x :: Maybe Int, y :: Maybe Text }
we can already create an applicative style in an applicative context (here IO) as
myfoo :: IO Foo myfoo = Foo <$> getEnvInt "someX" <*> getEnvText "someY"
Problem
What if someone prefers to build with explicit spelling of record field names? For example:
myfoo = Foo { x = getEnvInt "someX", y = getEnvText "someY" }
It will not look. One solution is
{-# LANGUAGE RecordWildCards #-} myfoo = do x <- getEnvInt "someX" y <- getEnvText "someY" return $ Foo {..}
It's not bad. But I wonder (for now, just for my own sake) if the following could work:
data FooC f = FooC { x :: f Int, y :: f Text } type Foo = FooC Maybe myfoo :: IO Foo myfoo = genericsMagic $ FooC { x = someEnvInt "someX" , y = someEnvText "someY" }
I believe that this can be done with a simple GHC.Generics pattern GHC.Generics , but this will not have type safety, so I was looking for a stronger approach. I came across generics-sop , which converts a record to a heterogeneous list and comes with a seemingly convenient hsequence operation.
Point where I'm stuck
generics-sop stores the Applicative type in a separate type parameter of its heterogeneous list, and this is always I (Identity) when using the generated transformation. So I would need to display the hlist and remove I from the elements that could effectively move the applicator under I to the specified type parameter (that would be Comp IO Maybe ), so I could use hsequence , and finally return I so that I can discreetly return to the recording.
But I do not know how to write a type signature for the delete / add function I , which reports that the types of the corresponding hlist elements are sequentially changed by losing / obtaining the external type. Is it possible?