问题的原因 人们可能会说zip
是Applicative
的一种方法,通常的例子是ZipList
。我不满意,因为它不安全。我也对Align
感到不满意,因为它由于包罗万象而变得过于复杂,并且对于常规情况而言不够具体。
合法类:Haskell中的某些类型类可能被称为 legacy 。这意味着它们带有必须满足的平等-阶级的法律。这些定律通常来自编程方面的范畴理论概念化。例如,Monad
是通过同义类别理论设备对计算 (无论什么意思)的概念。
重叠的东西
示例:
没有足够的定律。这个概念的概念化是通过单曲面函子和相应的Applicative
类型类实现的。但是,这有一个烦人的麻烦,因为通常有两种方法来定义Applicative
,而这两种方法似乎都适用。为什么这样?我建议答案是“法律不足” 。
示例:
用于算术:
Sum
Monoid是实际的“内-monoid” 。仅对亲属事物合法。例如,您不能求和求和。Product
Monoid将维数a
和b
的数目带到维数c
的数目。乘以质量和力量是合法的,这使我们感到温暖。因此,可以根据类型推断出正确的monoid选择。
对于列表:
ZipList
定义显然是不安全的。它的定义是,给定两个不同长度的列表,将较长的列表裁剪为较短的列表。zip
进行安全定义的设备。对于矩阵:
ZipMatrix
的定义类似于ZipList
上面看起来没有吸引力。Monad
的定义。两种情况:从这些示例中,它揭示出在我们称为“ monoid” 或” monoidal的事物中有两种截然不同的观念函子” ,并且区别对于编程非常重要(也许不像纯理论),因为它可以消除混乱,消除不安全因素,并且主要是因为在每种情况下,都有两种完全不相关的算法可以运行。
我认为单面函子的可逆性(也称为“强度” )很重要。但是,对Peano自然的求和和乘积等式运算的结果是无法区分的。 (我不确定它们是否可以被认为是类半角内生菌。)因此,我开始猜测类型的改变是其特征。物理量的乘法甚至不会将check键入为Monoid
!
PS 给出了Monad
的一个实例,用于表示笛卡尔乘积上的长度索引矢量和Kronecker乘积上的矩阵,其中fold zip
为{{1} }。
答案 0 :(得分:8)
可以通过safe表示确切的压缩(如the Representable
class包所称的那样)。与Representable
相关的理论很多。就目前的目的而言,我们可以专注于...
如果
Functor
和f
见证了Representable
的同构,则tabulate
index
为(->) x
。
...和:
Haskell类型类别中可代表的endofunctors对读者monad是同构的,因此可以免费继承大量属性。
由于Representable
函数对某种类型的函数是同构的(例如,同质对对Bool -> a
是同构的,而无限流对Nat -> a
是同构的),因此可以实现精确的压缩通过点按功能来压缩。这就是mzipRep
(MonadZip
的{{1}}的默认实现)
mzip
在MonadZip
is a rather awkward class(主要是mzipRep :: Representable f => f a -> f b -> f (a, b)
mzipRep as bs = tabulate (index as &&& index bs)
扩展的实现的一部分)中,它具有相关的法律,我将以非一语重述该法律:
信息保存:如果
MonadComprehensions
,则() <$ u = () <$ v
换句话说,如果munzip (mzip u v) = (u, v)
和u
的形状相同,则v
不会丢弃信息(因此mzip
可以撤消信息)。 munzip
暗示只有一种可能的形状,它使我们可以放下条件,从而获得精确的拉链。
相切注释:
Representable
定义显然是不安全的。它的定义是,给定两个长度不同的列表,将较长的列表裁剪为较短的列表。
我会说,这取决于您要使用拉链的用途。有时您会想要或需要精确的压缩,而有时则不需要(例如,考虑使用ZipList
将索引附加到列表的常见技巧);有时用填充而不是修剪是有意义的(参见leftaroundabout's comment)。这就是为什么我更喜欢将确切的压缩称为“精确”,而不是“安全”。
但是,这有一个烦人的麻烦,因为通常有两种方法来定义
zip [0..]
,而这两种方法都看起来很合适。为什么这样?我建议答案是“法律不足” 。
我非常不同意这样的观点,即如果某个类允许某些数据类型使用多个实例,则该类未指定。我宁愿说,例如带有笛卡尔乘积的应用列表和带有拉链合的应用的列表是不同的结构,其特征在于相关的形态学-碰巧它们可以通过相同的数据类型在Haskell中表示。