Я играл со свободными идеями и нашел это:
{-# LANGUAGE RankNTypes #-}
data Monoid m = Monoid { mempty :: m, mappend :: m -> m -> m }
data Generator a m = Generator { monoid :: Monoid m, singleton :: a -> m }
newtype Free f = Free { getFree :: forall s. f s -> s }
mkMonoid :: (forall s. f s -> Monoid s) -> Monoid (Free f)
mkMonoid f = Monoid {
mempty = Free (mempty . f),
mappend = \a b -> Free $ \s -> mappend (f s) (getFree a s) (getFree b s)
}
freeMonoid :: Monoid (Free Monoid)
freeMonoid = mkMonoid id
mkGenerator :: (forall s. f s -> Generator a s) -> Generator a (Free f)
mkGenerator f = Generator {
monoid = mkMonoid (monoid . f),
singleton = \x -> Free $ \s -> singleton (f s) x
}
freeGenerator :: Generator a (Free (Generator a))
freeGenerator = mkGenerator id
Я хотел бы найти условия, при которых я мог бы написать funcion:
mkFree :: (??? f) => f (Free f)
но мне не удалось найти значимую структуру для f
(кроме тривиальной, в которой mkFree
- метод ???
), который позволил бы записать эту функцию. В частности, мой эстетический смысл предпочел бы, чтобы эта структура не упоминала тип Free
.
Кто-нибудь видел что-то подобное раньше? Возможно ли это обобщение? Есть ли известное обобщение в том направлении, о котором я еще не думал?