与fmap具有相同多态类型的函数是否必须等于fmap?

时间:2019-04-15 14:23:46

标签: haskell functor

我正在阅读《 Haskell编程》第二版,偶然发现了这句话:

  

...只有一种方法可以将任何给定的参数化类型转换为函子,因此具有与fmap相同的多态类型的任何函数都必须等于fmap

这对我来说似乎不对。我可以看到每种fmap类型只有Functor valid 定义,但是可以肯定的是,我可以用(a -> b) -> f a -> f b类型定义任意数量的函数彼此不相等吗?

为什么会这样?或者,这仅仅是作者的一个错误?

3 个答案:

答案 0 :(得分:9)

您误解了作者在说什么。

  

...具有fmap相同的多态类型的任何函数 ...

这意味着具有签名的任何功能

Functor f => (a -> b) -> f a -> f b

必须等于fmap。 (当然,除非您允许最低值。)

那句话是真的;如果您尝试定义这样的函数,则很容易看到:因为对f一无所知,除了它是一个函子,获取非obtain f b值的唯一方法是通过映射f a

引号中的逻辑含义不太清楚:

  

只有一种方法可以将任何给定的参数化类型转换为函子,并且因此与fmap具有相同多态类型的任何函数都必须等于fmap。

我认为作者的意思是,因为Functor f => (a -> b) -> f a -> f b函数必须调用fmap,并且因为fmap始终是唯一的有效函子-在映射参数化类型时,实际上,任何Functor f => (a -> b) -> f a -> f b也会遵守函子定律,即它将是 the fmap

我同意“因此”的措词有点不好,但原则上引用是正确的。

答案 1 :(得分:4)

我认为引言是指这种情况。假设我们定义了一个参数化类型:

data F a = .... -- whatever

我们不仅可以为其编写一个实现,而且可以编写两个fmap实现

fmap1 :: (a -> b) -> F a -> F b
fmap2 :: (a -> b) -> F a -> F b

满足函子律

fmap1 id = id
fmap1 (f . g) = fmap1 f . fmap1 g
fmap2 id = id
fmap2 (f . g) = fmap2 f . fmap2 g

在这些假设下,我们拥有fmap1 = fmap2

这是与fmap的多态类型相关的“自由定理”的理论结果(请参见Lemma 1下的注释)。 务实地,这确保了我们从deriving Functor获得的实例是唯一可能的实例。

答案 2 :(得分:2)

这是一个错误。对于不是fmap的列表,下面是一些与fmap类型相同的函数的示例:

\f -> const []
\f -> concatMap (replicate 2 . f)
\f -> map (f . head) . chunksOf 2
\f -> map f . reverse

还有更多。通常,给定功能ixf,从列表长度到不大于该长度的数字列表(即列表中的有效索引),我们可以构建

maybeIt'sFmapLol :: (Int -> [Int]) -> (a -> b) -> [a] -> [b]
maybeIt'sFmapLol ixf elemf xs = [map elemf xs !! ix | ix <- ixf (length xs)]

使用Int的适当惰性变体来处理无限列表。可以为其他类似容器的函子构造类似的功能模式。