Free Monoid和Monoid之间的主要区别是什么?

时间:2019-01-12 22:13:33

标签: haskell functional-programming category-theory monoids

好像我很清楚地了解this.state.initialPos在Haskell中是什么,但是上次我听说了一个叫做免费类半身像的东西。

什么是免费的半身像,它与一个半身像有什么关系?

您可以在Haskell中提供示例吗?

4 个答案:

答案 0 :(得分:10)

在编程环境中,我通常将 free monoid 转换为[a]。 Bartosz Milewski在他的有关category theory for programmers的精彩文章系列中,将Haskell中的free monoids描述为列表半等式(假设一个人忽略了无限列表的某些问题)。

identity元素为空列表,二进制操作为列表串联:

Prelude Data.Monoid> mempty :: [Int]
[]
Prelude Data.Monoid> [1..3] <> [7..10]
[1,2,3,7,8,9,10]

直觉上,我认为此monoid是“免费的”,因为无论您要使用哪种价值类型,您都可以始终应用此monoid(就像免费monad是您可以始终从任何仿函数创建的一个monad。

另外,当一个类型存在一个以上的monoid时,自由的monoid将推迟使用哪个特定的monoid的决定。例如,对于整数,存在无限多的类四面体,但最常见的是加法和乘法。

如果您有两个(或多个整数),并且知道可能要对其进行汇总,但尚未决定要应用哪种类型的汇总,则可以使用免费的“汇总”它们monoid-实际上,这意味着将它们放在列表中:

Prelude Data.Monoid> [3,7]
[3,7]

如果您以后决定要将它们添加在一起,则可以:

Prelude Data.Monoid> getSum $ mconcat $ Sum <$> [3,7]
10

相反,如果您希望将它们相乘,也可以这样做:

Prelude Data.Monoid> getProduct $ mconcat $ Product <$> [3,7]
21

在这两个示例中,我故意选择将每个数字提升为体现更具体的类半体的类型(SumProduct),然后使用mconcat来执行聚集。

对于加法和乘法,有更多简洁的方法可以做到这一点,但是我这样做是为了说明如何使用更具体的monoid来解释自由monoid。

答案 1 :(得分:10)

您已经知道,monoid是一个集合,其中元素e和操作<>满足

e <> x = x <> e = x  (identity)
(x<>y)<>z = x<>(y<>z)  (associativity)

现在,直观上是 free 的等分体,是仅满足上述等式以及它们所有后果的等分体。

例如,Haskell列表等式([a], [], (++))是免费的。

相比之下,Haskell总和二等式(Sum Int, Sum 0, \(Sum x) (Sum y) -> Sum (x+y))不是自由的,因为它还满足其他方程式。例如,它是可交换的

x<>y = y<>x

这不是从前两个方程式得出的。

请注意,在数学上可以证明,所有自由单边形与列表单边形[a]是同构的。因此,编程中的“免费monoid”只是任何一种数据结构的奇特名词,这些数据结构可以1)转换为列表,然后返回而又不丢失信息,并且2)反之亦然,可以将列表转换为它,往返,不会丢失任何信息。

在Haskell中,您可以在心理上用“类似列表的类型”代替“自由monoid”。

答案 2 :(得分:4)

一个自由的类人动物是一种特殊类型的类人动物。具体来说,就是通过将一组固定的元素作为字符,然后从这些元素形成所有可能的字符串来获得的Monoid。这些字符串,其基本操作是字符串连接,形成一个monoid,该monoid称为自由monoid。

答案 3 :(得分:4)

monoid (M,•,1)是如下数学结构:

  1. M是一组
  2. 1M的成员
  3. • : M * M -> M
  4. a•1 = a = 1•a
  5. 给定a中的元素bcM,我们有a•(b•c) = (a•b)•c

集合M上的一个自由的monoid是一个(M',•,0)和一个函数e : M -> M'的一个monoid,因此,对于任何(N,*,1)的monoid,给定一个(集合)映射{{1 }}我们可以将其扩展为一个半同态射影f : M -> N,即

f' : (M',•,0) -> (N,*,1)

换句话说,这是一个没有特别之处的单面体。

一个简单的monoid实例是整数,其运算为加法运算,且标识为0。另一个monoid是整数序列,其运算为串联运算,且其标识为空序列。现在,加法运算中的整数不是整数上的自由monoid。将映射考虑为取f a = f' (e a) f' 0 = 1 f' (a•b) = (f' a) • (f' b) n的整数序列。然后,为了使它免费,我们需要将其扩展到将(n)n + m的地图,即,它必须将(n,m)0(0)并转到(0,0),依此类推。

另一方面,如果我们尝试将整数序列看做是整数上的自由单边形,那么在这种情况下它似乎可以工作。通过加法将映射扩展为整数是一种将序列之和(()的总和为0)。

那么集合(0,0,0)上的免费monoid是什么?我们可以尝试的一件事就是S的任意二叉树。在Haskell类型中,它看起来像:

S

它将具有data T a = Unit | Single a | Conc (T a) (T a) Unite = Single的身份。

我们可以编写一个函数来显示它是如何免费的:

(•) = Conc

很明显,这满足了-- here the second argument represents a monoid structure on b free :: (a -> b) -> (b -> b -> b, b) -> T a -> b free f ((*),zero) = f' where f' (Single a) = f a f' Unit = zero f' (Conc a b) = f' a * f' b 上的免费monoid所必需的法律。除以下一项外:a不是一个单面体,因为它不能完全满足定律4或5。

所以现在我们应该问是否可以将其变成一个更简单的自由类半体,即一个实际的类半体。答案是肯定的。一种方法是观察T aConc Unit aConc a Unit应该相同。因此,让前两种类型无法表示:

Single a

我们可以做的第二个观察是,data TInner a = Single a | Conc (TInner a) (TInner a) data T a = Unit | Inner (TInner a) Conc (Conc a b) c之间应该没有区别。这是由于上述法律5所致。然后我们可以展平我们的树:

Conc a (Conc b c)

data TInner a = Single a | Conc (a,b,[a]) data T a = Unit | Inner (TInner a) 力的奇怪构造是只能用一种方式来表示ConcSingle a。但是我们看到可以将所有这些合并在一起:将Unit的定义更改为Conc,然后将Conc [a]更改为Single x,将Conc [x]更改为{ {1}},我们有:

Unit

或者我们可以这样写:

Conc []

操作如下:

data T a = Conc [a]

因此在Haskell中,列表类型称为自由类半身像。