自由组monad

时间:2016-08-26 08:10:38

标签: haskell monads category-theory

在范畴论中,monad是两个伴随函子的组合。例如,Maybe monad是由遗忘函子组成的自由尖集函子。同样,List monad是由遗忘函子组成的免费monoid函子。

Monoid是最简单的代数结构之一,所以我想知道编程是否可以从更复杂的代数中受益。我没有在标准Haskell包中找到自由组monad,所以我将在这里定义

data FreeGroup a = Nil | PosCons a (FreeGroup a) | NegCons a (FreeGroup a)

==运算符定义为NegCons x (PosCons x y) == y。因此,在length :: FreeGroup a -> Int中,每个PosCons计为+1,每个NegCons -1(它是Int的唯一群组态射,每个PosCons的值+1)。

与列表(免费幺半群)一样,concat只是乘法而map是函数的函数提升。因此FreeGroup的monad实例与List的实例完全相同。

免费群组monad是否有任何编程用途?此外,通常会将monad解释为上下文中的值:对于List,上下文将是选择或不确定。对于自由组monad有没有这样的解释?

免费铃声和矢量空间(总是免费的)怎么样?

对于任何代数结构Scategorical free functor FS :: Set -> S的存在意味着存在一个函数Haskell调用fold:

foldS :: S s => (a -> s) -> FS a -> s

它将基于a的函数提升为S - 自由对象FS a上的态射。通常的foldr函数是foldMonoid的特化(在Haskell中称为foldMap,由于某些原因我不太了解),monoid是函数集b -> b用组合作为乘法。

为了完整起见,这是FreeGroup

的monad实例
mult :: FreeGroup a -> FreeGroup a -> FreeGroup a
mult Nil x = x
mult x Nil = x
mult (PosCons x y) z = PosCons x (mult y z)
mult (NegCons x y) z = NegCons x (mult y z)

inverse :: FreeGroup a -> FreeGroup a
inverse Nil = Nil
inverse (PosCons x y) = mult (inverse y) (NegCons x Nil)
inverse (NegCons x y) = mult (inverse y) (PosCons x Nil)

groupConcat :: FreeGroup (FreeGroup a) -> FreeGroup a
groupConcat Nil = Nil
groupConcat (PosCons x l) = mult x (groupConcat l)
groupConcat (NegCons x l) = mult (inverse x) (groupConcat l)

instance Functor FreeGroup where
  fmap f Nil = Nil
  fmap f (PosCons x y) = PosCons (f x) (fmap f y)
  fmap f (NegCons x y) = NegCons (f x) (fmap f y)

instance Applicative FreeGroup where
  pure x = PosCons x Nil
  fs <*> xs = do { f <- fs; x <- xs; return $ f x; }

instance Monad FreeGroup where
  l >>= f = groupConcat $ fmap f l

1 个答案:

答案 0 :(得分:1)

“免费群组monad是否有任何编程用途?”

由于过去四个月缺乏答案,我认为答案是“不,不是真的”。但这是一个有趣的问题,因为它基于基本的数学概念,在我看来(也)它应该。

首先我注意到,建议的免费群组功能也可以通过列表中的a a,

轻松实现
type FreeGroupT a = [Either a a]

fgTofgT :: FreeGroup a -> FreeGroupT a
fgTofgT Nil = []
fgTofgT (a :+: as) = Right a : fgToList as
fgTofgT (a :-: as) = Left a : fgToList as

fgTTofg :: FreeGroupT a -> FreeGroup a
fgTTofg [] = Nil
fgTTofg (Right a : as) = a :+: fgTTofg as
fgTTofg (Left a : as) = a :-: fgTTofg as

--using (:-:) instead of NegCons
--and   (:+:) instead of PosCons

这是一个很好的定义,因为我们确保我们的自由组只是一个具有一点额外结构的幺半群。它呼吁自由群体只是一个自由幺半群的组合与另一个仿函数(名称是什么?不是一个b bifunctor而是一个仿函数F a = L a | R a)。我们还确保自由组monad实例与自由monoid的monad实例一致。也就是说,自由组上的monad操作的条件恰好都是正数,应该像自由monoid上的monad一样,对吗?

但是,最终,如果我们想要减少逆,我们需要一个Eq a实例。我们需要在学期一级工作,纯类型信息是不够的。这使得自由幺半群和自由群体之间的类型级别区别无益 - 据我所见。至少不依赖于打字。

为了讨论实际的编程用法,我会尝试(但不能)提供合理的用例。

想象一个文本编辑器,它使用“Ctrl”键来指示命令序列。按住“Ctrl”时按下的任何键序列都被建模为FreeGroup中的底片(负面缺点(: - :))。因此,可以使用自由组术语'a':+:'b':+:'b':-:'a':-:[]来模拟编写“ab”的emacs行为,将光标移回字符,然后移动到行的开头。这样的设计很好。我们可以轻松地在流中嵌入命令和宏,而不需要一些特殊的保留转义字符。

但是,此示例作为正确的用例失败,因为我们希望'a':+:'b':+:'b':-:'a':-:[][]是同一个程序,而不是Numbers Names 123 AA 124 AB 125 AC 126 AD 127 BB 128 BC 129 BD 130 CC 131 CD 132 DD 。此外,它很容易,只需将每个列表术语包装在Either中,如上所述。