什么是协变函子?

zer*_*ing 8 haskell

我想了解一下,为什么这样的Maybe类型是协变函子?

协变量是什么意思?

请提供示例进行说明。

bra*_*drn 15

一个函子只是普通Functor类:

class Functor f where
    fmap :: (a -> b) -> f a -> f b
Run Code Online (Sandbox Code Playgroud)

例如,Maybe(如您所述):

instance Functor Maybe where
    fmap _ Nothing = Nothing
    fmap f (Just a) = Just (f a)
Run Code Online (Sandbox Code Playgroud)

但是,还有另一种函子:函子。这些定义如下:

class Contravariant f where
    contramap :: (a -> b) -> f b -> f a
Run Code Online (Sandbox Code Playgroud)

请注意,与相比fmapcontramap已颠倒了b和的顺序a

fmap      ::       Functor f => (a -> b) -> f a -> f b
contramap :: Contravariant f => (a -> b) -> f b -> f a
                                         --   ^      ^
                                         --   look!
Run Code Online (Sandbox Code Playgroud)

现在,这个疯狂的Contravariant班级甚至有任何实例吗?嗯,是。例如,这是a的定义Predicate

newtype Predicate x = Predicate { decide :: x -> Bool }
Run Code Online (Sandbox Code Playgroud)

换句话说,a Predicate x是一个计算条件的函数x。我们可以专注contramapPredicate

contramap :: (a -> b) -> Predicate b -> Predicate a
Run Code Online (Sandbox Code Playgroud)

等效于:

contramap :: (a -> b) -> (b -> Bool) -> (a -> Bool)
Run Code Online (Sandbox Code Playgroud)

基本上,给定一个Predicateon bs和从as b s 的映射,就contramap可以得到Predicateon a。(我将把实现留为练习。)这是一个示例(未经测试):

hasMultChars :: Predicate String
hasMultChars = Predicate $ \x -> length x > 1

showInt :: Int -> String
showInt = show

intHasMultChars :: Predicate Int
intHasMultChars = contramap showInt hasMultChars
Run Code Online (Sandbox Code Playgroud)

事实证明,与正常的协变函子相比,协变函子不那么常见,因此也没有那么有用。因此,实际上,我们忽略了“协变量”,因为在大多数情况下它不会添加任何内容。


lef*_*out 5

协变函子是 \xe2\x80\x9cinside\xe2\x80\x9d 和 \xe2\x80\x9coutside\xe2\x80\x9d 箭头指向同一方向的函子。

\n\n
class Functor f where\n  fmap :: (a -> b) -> (f a -> f b)\n
Run Code Online (Sandbox Code Playgroud)\n\n

逆变函子是 \xe2\x80\x9cinside\xe2\x80\x9d 和 \xe2\x80\x9coutside\xe2\x80\x9d 箭头指向相反方向的函子。

\n\n
class Contravariant f where\n  contramap :: (a -> b) -> (f a <- f b)\n
Run Code Online (Sandbox Code Playgroud)\n\n

...或者,使用正确的 Haskell 语法,

\n\n
  contramap :: (a -> b) -> (f b -> f a)\n
Run Code Online (Sandbox Code Playgroud)\n\n

这通常表明参数类型作为数据类型中的函数参数出现在某个地方,例如

\n\n
data DepInt x = DepInt (x -> Int)\n\ninstance Contravariant DepInt where\n  contramap f (DepInt g) = DepInt $ g . f\n
Run Code Online (Sandbox Code Playgroud)\n\n

相反,如果参数仅按原样出现或出现在函数箭头的右侧,则它是协变函子。大多数函子都是这种情况,这就是为什么该类被简单地称为Functor.

\n

  • @bradrn,除非“co”后面跟着“variant”! (3认同)
  • 一般来说,共同“某物”是箭头相反的“某物”。 (2认同)
  • @David 是的,共同函子与函子相同。如果反转 `fmap :: Functor f =&gt; (a -&gt; b) -&gt; fa -&gt; fb` 上的箭头,则会得到 `co_fmap :: CoFunctor f =&gt; (a &lt;- b) -&gt; (fa &lt;- fb)`,与 `co_fmap :: CoFunctor f =&gt; (b -&gt; a) -&gt; (fb -&gt; fa)` 相同 - 与 `fmap` 相同。(反思我的评论,我什至不确定我为什么这么做!问题或这个答案中都没有提到共同的东西,所以唯一合理的解释是我当时产生了幻觉......) (2认同)