Haskell 自由幺半群和幺半群的主要区别是什么?
看起来我对Haskell中的Haskell 自由幺半群和幺半群的主要区别是什么?,haskell,functional-programming,category-theory,monoids,Haskell,Functional Programming,Category Theory,Monoids,看起来我对Haskell中的幺半群有了相当清晰的理解,但上次我听说了一个叫做自由幺半群的东西 什么是自由幺半群,它与幺半群有什么关系 你能在Haskell中提供一个例子吗?自由幺半群是一种特定类型的幺半群。具体地说,它是通过将一些固定的元素集作为字符,然后从这些元素中形成所有可能的字符串而得到的幺半群。这些字符串(底层操作是字符串连接)形成一个幺半群,该幺半群称为自由幺半群。在编程上下文中,我通常将自由幺半群转换为[a]。Bartosz Milewski在关于的优秀系列文章中,在Haskell中
幺半群
有了相当清晰的理解,但上次我听说了一个叫做自由幺半群的东西
什么是自由幺半群,它与幺半群有什么关系
你能在Haskell中提供一个例子吗?自由幺半群是一种特定类型的幺半群。具体地说,它是通过将一些固定的元素集作为字符,然后从这些元素中形成所有可能的字符串而得到的幺半群。这些字符串(底层操作是字符串连接)形成一个幺半群,该幺半群称为自由幺半群。在编程上下文中,我通常将自由幺半群转换为
[a]
。Bartosz Milewski在关于的优秀系列文章中,在Haskell中将列表幺半群描述为列表幺半群(假设忽略了无限列表的一些问题)
标识元素为空列表,二进制操作为列表串联:
Prelude Data.Monoid> mempty :: [Int]
[]
Prelude Data.Monoid> [1..3] <> [7..10]
[1,2,3,7,8,9,10]
如果您以后决定将它们添加到一起,则有可能:
Prelude Data.Monoid> getSum $ mconcat $ Sum <$> [3,7]
10
Prelude Data.Monoid>getSum$mconcat$Sum[3,7]
10
如果您希望将它们相乘,也可以这样做:
Prelude Data.Monoid> getProduct $ mconcat $ Product <$> [3,7]
21
Prelude Data.Monoid>getProduct$mconcat$Product[3,7]
21
在这两个示例中,我特意选择将每个数字提升为包含更具体幺半群的类型(Sum
,Product
),然后使用mconcat
执行聚合
对于加法和乘法,有更简洁的方法,但我这样做是为了说明如何使用更具体的幺半群来解释自由幺半群。幺半群(M,•,1)
是一种数学结构,如下所示:
M
是一个集合1
是M
•:M*M->M
a•1=a=1•a
M
中的a
、b
和c
元素,我们有a•(b•c)=(a•b)•c
M
上的自由幺半群是一个幺半群(M',•,0)
和函数e:M->M'
,对于任何幺半群(N,*,1)
,给定一个(集)映射f:M->N
,我们可以将其推广到一个幺半群同态f':(M',•,0)->(N,*,1)
,即
f a = f' (e a)
f' 0 = 1
f' (a•b) = (f' a) • (f' b)
换句话说,它是一个没有特殊作用的幺半群
例如,幺半群是运算为加法且恒等式为0的整数。另一个幺半群是整数序列,其操作为串联,标识为空序列。现在加法下的整数不是整数上的自由幺半群。将该映射视为整数序列,采用<代码> n>代码> >代码>(n)< /代码>。然后,为了使这是免费的,我们需要将它扩展到一个将n+m
映射到(n,m)
,也就是说,它必须将0
映射到(0)
和(0,0)
以及(0,0)
等等
另一方面,如果我们试着把整数序列看作是整数上的自由幺半群,我们会发现它在这种情况下似乎是有效的。将映射扩展为带加法的整数是一个取序列之和的扩展(其中()之和为0)
那么集S
上的自由幺半群是什么呢?我们可以尝试的一件事就是任意的S
二叉树。在Haskell类型中,这看起来像:
data T a = Unit | Single a | Conc (T a) (T a)
它的标识为单位
,e=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
很明显,这满足了a
上自由幺半群所需的定律。除了一个:ta
不是幺半群,因为它不完全满足第4或第5定律
所以现在我们应该问,我们是否可以把它变成一个更简单的自由幺半群,也就是一个实际的幺半群。答案是肯定的。一种方法是观察Conc Unit a
和Conc Unit
和单个a
应相同。因此,让我们将前两种类型设置为不可表示:
data TInner a = Single a | Conc (TInner a) (TInner a)
data T a = Unit | Inner (TInner a)
我们可以做的第二个观察是,Conc(Conc A b)c
和Conc A(Conc b c)
之间应该没有区别。这是由于上述第5条。然后我们可以把树压平:
data TInner a = Single a | Conc (a,TInner a)
data T a = Unit | Inner (TInner a)
Conc
的奇怪结构迫使我们只能用一种方式来表示单个a
和单元
。但是我们看到我们可以将这些合并在一起:将Conc
的定义更改为Conc[a]
,然后我们可以将Single x
更改为Conc[x]
,将Unit
更改为Conc[]
,因此我们有:
data T a = Conc [a]
或者我们可以写:
type T a = [a]
行动包括:
unit = []
e a = [a]
(•) = append
free f ((*),zero) = f' where
f' [] = zero
f' (x:xs) = f x * f' xs
因此在Haskell中,列表类型被称为自由幺半群。正如您已经知道的,幺半群是一个集合,包含一个元素
e
和一个操作
e <> x = x <> e = x (identity)
(x<>y)<>z = x<>(y<>z) (associativity)
这不是前两个方程的结果
注意,在数学中可以证明,所有自由幺半群同构于列表幺半群[a]
。因此,编程中的“自由幺半群”对于任何数据结构来说只是一个花哨的术语,1)可以转换为列表,然后返回,不会丢失信息;2)反之亦然,列表可以转换为列表,然后返回,不会丢失信息
在Haskell中,你可以用“类似列表的类型”替换“自由幺半群”。这是一个数学问题吗?也许它更适合@Coderino-Javarino,我更喜欢从编程的角度给出答案。我想我没有足够的能力去理解数学人的反应。如果我找不到回应,我一定会去那里试试。谢谢编程的观点是,这不是一个编程问题:-)(范畴理论是为理论计算机科学家而提出的。)事实上,幺半群起源于m
e <> x = x <> e = x (identity)
(x<>y)<>z = x<>(y<>z) (associativity)
x<>y = y<>x