Typeclassopedia说:
“类似的论点也表明,任何满足第一定律(fmap id = id)的函数器实例也将自动满足第二定律。实际上,这意味着只需要检查第一定律(通常通过非常简单的归纳),以确保函数器实例是有效的。”
如果是这样的话,为什么我们还要提到第二函子定律呢?
Law 1: fmap id = id
Law 2: fmap (g . h) = (fmap g) . (fmap h)发布于 2011-11-29 13:29:03
虽然我不能给出证明,但我相信这是在说,由于,只要第一定律成立,类型系统就会强制执行第二定律。指定这两个规则的原因是,在更一般的数学设置中,您可能有一些类别C,其中完全可以定义从C到其自身的“映射”(即,分别在Obj(C)和Hom(C)上的一对内部函数),该映射遵守第一条规则,但不符合第二条规则,因此无法构成函数器。
请记住,Haskell中的Functor是Hask类别上的内部函数器,甚至不是所有在Hask上数学上被认为是内部函数器的东西都可以用Haskell来表示。参数多态性的约束排除了能够为它映射的所有对象(类型)指定一个不统一行为的函数器的可能性。
基于this thread,普遍的共识似乎是,对于Haskell Functor实例,第二个定律遵循第一个定律。Edward Kmett says
对于给定的fmap id = id,fmap (f . g) = fmap f . fmap g由
的自由定理推导而来。
这篇文章发表在很久以前的一篇论文中,但我忘了在哪里。
发布于 2011-11-30 16:53:03
使用seq,我们可以编写一个满足第一个规则但不满足第二个规则的实例。
data Foo a = Foo a
deriving Show
instance Functor Foo where
fmap f (Foo x) = f `seq` Foo (f x)我们可以验证这是否满足第一定律:
fmap id (Foo x)
= id `seq` Foo (id x)
= Foo (id x)
= Foo x然而,它违反了第二定律:
> fmap (const 42 . undefined) $ Foo 3
Foo 42
> fmap (const 42) . fmap undefined $ Foo 3
*** Exception: Prelude.undefined也就是说,我们通常会忽略这些病态的案例。
发布于 2011-11-29 13:20:39
我要说的是,第二定律不是出于有效性的原因,而是作为一个重要的性质而提到的:
第一定律说,在容器中的每一项上映射标识函数没有任何效果。第二种方法是将两个函数的组合映射到容器中的每个项上,这与先映射一个函数,然后再映射另一个函数相同。-类型性百科全书
(我不明白为什么第一定律意味着第二定律,但我不是一个熟练的Haskeller -当你知道发生了什么时,它可能是显而易见的)
https://stackoverflow.com/questions/8305949
复制相似问题