好像我很清楚地了解this.state.initialPos
在Haskell中是什么,但是上次我听说了一个叫做免费类半身像的东西。
什么是免费的半身像,它与一个半身像有什么关系?
您可以在Haskell中提供示例吗?
答案 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
在这两个示例中,我故意选择将每个数字提升为体现更具体的类半体的类型(Sum
,Product
),然后使用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)
是如下数学结构:
M
是一组1
是M
的成员• : M * M -> M
a•1 = a = 1•a
a
中的元素b
,c
和M
,我们有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)
,Unit
和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
上的免费monoid所必需的法律。除以下一项外:a
不是一个单面体,因为它不能完全满足定律4或5。
所以现在我们应该问是否可以将其变成一个更简单的自由类半体,即一个实际的类半体。答案是肯定的。一种方法是观察T a
和Conc Unit a
和Conc 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)
力的奇怪构造是只能用一种方式来表示Conc
和Single a
。但是我们看到可以将所有这些合并在一起:将Unit
的定义更改为Conc
,然后将Conc [a]
更改为Single x
,将Conc [x]
更改为{ {1}},我们有:
Unit
或者我们可以这样写:
Conc []
操作如下:
data T a = Conc [a]
因此在Haskell中,列表类型称为自由类半身像。