I am using barbies-th
to turn a record type into a higher-kinded datatype:
declareBareB [d|
data Foo = MkFoo
{ field1 :: Int
, field2 :: Bool
} |]
I can then write a function to push any applicative effect into individual fields:
bdistribute :: (Applicative f) => f (Foo Bare Identity) -> Foo Covered f
bdistribute foo = MkFoo
{ field1 = field1 <$> foo
, field2 = field2 <$> foo
}
But it feels like I should be able to write bdistribute
once and for all for all Barbie-style HKDs. In other words, I am looking for the dual of Higgledy's construct
. Higgledy has these two methods in the Construct
typeclass:
construct :: HKD structure f -> f structure
deconstruct :: structure -> HKD structure f
but I'd like
nstruct :: (Applicative f) => f structure -> HKD structure f
Brainstorming below: one idea I just had is that this problem can be simplified into writing the following function generically:
shape :: Foo Covered ((->) (Foo Bare Identity))
shape = MkFoo
{ field1 = field1
, field2 = field2
}
since then we have
bdistribute :: (Applicative f) => f (Foo Bare Identity) -> Foo Covered f
bdistribute = bmap (<$> x) shape
More generally, from shape
we can also write
bdistribute :: (Functor f, Applicative g, ApplicativeB b, TraversableB b) => f (b g) -> b (Compose f g)
bdistribute x = bmap (\f -> Compose $ fmap f . bsequence' <$> x) shape
I ended up adding a DistributiveB
typeclass
to the Barbies package, available since 2.0.1.0:
class FunctorB b => DistributiveB (b :: (k -> Type) -> Type) where
bdistribute :: Functor f => f (b g) -> b (Compose f g)
To recover the shape
function from my original question, we can use the following specialized version of bdistribute
:
bdecompose :: DistributiveB b => (a -> b Identity) -> b ((->) a)
This gives us shape = bdecompose id