我正在玩着类似自由的想法,并发现了这个:
{-# 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
我想找到一个可以编写功能的条件:
mkFree :: (??? f) => f (Free f)
但是我无法为f
找到一个有意义的结构(除了mkFree
是???
的方法之外的简单结构),这将允许写入此函数。特别是,如果这个结构没有提到Free
类型,我的审美意识会更喜欢。
有没有人见过这样的东西?这种概括可能吗?在我尚未想到的方向上有一个已知的概括吗?
答案 0 :(得分:8)
与通用代数的联系是一个很好的起点,在阅读之后,一切都落到了位置。我们正在寻找的是F代数:
type Alg f x = f x -> x
用于任何(endo)仿函数f
。例如,对于Monoid代数,仿函数是:
data MonoidF m = MEmpty | MAppend m m deriving Functor
对于任何Monoid
实例,都有明显的幺半群代数:
monoidAlg :: Monoid m => Alg MonoidF m
monoidAlg MEmpty = mempty
monoidAlg (MAppend a b) = mappend a b
现在我们可以从free-functors包中获取free functor定义,并用f-algebra替换类约束:
newtype Free f a = Free { runFree :: forall b. Alg f b -> (a -> b) -> b }
在某种意义上,自由仿函数是将任何集a
转换为代数的最佳方法。这是如何:
unit :: a -> Free f a
unit a = Free $ \_ k -> k a
这是最好的方法,因为通过任何其他方式将a
转换为代数b
,我们可以将免费代数中的函数赋予b
:
rightAdjunct :: Functor f => Alg f b -> (a -> b) -> Free f a -> b
rightAdjunct alg k (Free f) = f alg k
剩下的就是实际显示自由仿函数创建了一个f代数(这就是你要求的):
freeAlg :: Functor f => Alg f (Free f a)
freeAlg ff = Free $ \alg k -> alg (fmap (rightAdjunct alg k) ff)
稍微解释一下:ff
的类型为f (Free f a)
,我们需要构建一个Free f a
。如果我们可以构建b
,给定alg :: f b -> b
和k :: a -> b
,我们就可以做到这一点。因此,如果我们可以将alg
包含的每个ff
映射到Free f a
,我们就可以将b
应用于rightAdjunct
,但这正是alg
对k
的作用}和Free f
。
正如您可能已经猜到的那样,f
是仿函数instance Functor f => Monad (Free f) where
return = unit
m >>= f = rightAdjunct freeAlg f m
上的免费monad(确切地说是church encoded version。)
{{1}}