有人声称newtype T a = T (a -> Int)
是一个不是仿函数的类型构造函数(但它是一个逆变函子)。怎么会这样?或者什么是逆变函子(我认为这很明显为什么它不能成为普通函子)?
答案 0 :(得分:6)
假设T是一个仿函数。然后我们有
fmap :: (a -> b) -> T a -> T b
现在,让我们尝试实施它。
instance Functor T where
fmap f (T g) = T $ \x -> _y
显然,我们从这样的事情开始,并以某种方式合并值f
,g
和x
以计算y
的{{1}}值。正确的类型。我们怎么做?好吧,请注意我称之为_y
,这告诉GHC我需要一些帮助来确定放在那里的内容。 GHC有什么要说的?
<interactive>:7:28: error:
• Found hole: _y :: Int
Or perhaps ‘_y’ is mis-spelled, or not in scope
• In the expression: _y
In the second argument of ‘($)’, namely ‘\ x -> _y’
In the expression: T $ \ x -> _y
• Relevant bindings include
x :: b (bound at <interactive>:7:23)
g :: a -> Int (bound at <interactive>:7:13)
f :: a -> b (bound at <interactive>:7:8)
fmap :: (a -> b) -> T a -> T b (bound at <interactive>:7:3)
所以现在我们要清楚所有相关的类型,对吗?我们需要以某种方式返回Int
,我们必须构建它是:
x :: b
g :: a -> Int
f :: a -> b
嗯,好吧,我们唯一能够创建Int
的{{1}}就是g
,所以让我们把它填入,留下g
&#39; s参数空白,要求GHC提供更多帮助:
instance Functor T where
fmap f (T g) = T $ \x -> g _y
<interactive>:7:31: error:
• Found hole: _y :: a
Where: ‘a’ is a rigid type variable bound by
the type signature for:
fmap :: forall a b. (a -> b) -> T a -> T b
at <interactive>:7:3
Or perhaps ‘_y’ is mis-spelled, or not in scope
• In the first argument of ‘g’, namely ‘(_y)’
In the expression: g (_y)
In the second argument of ‘($)’, namely ‘\ x -> g (_y)’
• Relevant bindings include
x :: b (bound at <interactive>:7:23)
g :: a -> Int (bound at <interactive>:7:13)
f :: a -> b (bound at <interactive>:7:8)
fmap :: (a -> b) -> T a -> T b (bound at <interactive>:7:3)
好的,我们可以自己预测:要调用g
,我们需要从某处获得a
类型的值。但是我们在范围内没有a
类型的任何值,并且我们也没有任何返回a
类型值的函数!我们陷入困境:现在不可能产生我们想要的类型的价值,尽管我们每一步都做了唯一可行的事情:我们没有任何东西可以备份并尝试不同的方式。
为什么会这样?因为如果我给你一个a -> Int
类型的函数并且说'#34;但顺便说一句,这里是a -> b
的函数,请给我一个来自b -> Int
的函数相反&#34;,你实际上使用来自a -> b
的功能,因为没有人给你任何a
来调用它!如果我从b -> a
给你一个函数,那将非常有用,对吧?您可以从b -> Int
生成一个函数,然后首先调用b -> a
函数获取a
,然后调用原始a -> Int
函数以获取所需的Int
1}}。
这就是逆变函子的意义所在:我们将传递给fmap
的函数中的箭头反转,因此它可以映射你需要的东西&#34; (函数参数)而不是你&#34;有&#34; (具体值,函数的返回值等)。
除此之外:我之前声称我们已经做过&#34;唯一可能的事情&#34;在每一步,这有点像。我们无法在Int
,f
和g
中构建x
,但当然我们可以在空中弥补各种数字。我们对类型b
一无所知,因此我们无法以某种方式获得Int
来自它的instance Functor T where
fmap f (T g) = T $ const 0
,但我们只能说&# 34;让我们总是返回零&#34;,这在技术上满足了类型检查器:
f
显然这看起来很错误,因为看起来g
和fmap id = id
应该非常重要,我们忽略了它们!但它是类型检查,所以我们没问题,对吧?
不,这违反了Functor法律之一:
fmap id (T $ const 5) = (T $ const 0) /= (T $ const 5)
我们可以很容易地证明这一点:
Int
现在我们真的已经尝试了一切:我们必须在不使用b
类型的情况下构建const
的唯一方法就是从无到有,所有此类用途都与使用function setPrimeLimits() {
var selectedStart = $('#space_global_start').val();
var selectedEnd = $('#space_global_end').val();
$('#prime_global_start, #prime_global_end').timepicker({
minTime: selectedStart,
maxTime: selectedEnd,
});
}
$('#space_global_start, #space_global_end').on('changeTime', setPrimeLimits);
同构,这将违反Functor法律。
答案 1 :(得分:6)
鉴于
newtype T a = T (a -> Int)
让我们尝试为此数据类型构建Contravariant
实例。
这是所讨论的类型类:
class Contravariant f where
contramap :: (a -> b) -> f b -> f a
基本上,contramap
类似于fmap
,但不是将函数a -> b
提升为f a -> f b
,而是将其提升为f b -> f a
。
让我们开始编写实例......
instance Contravariant T where
contramap g (T f) = ?
在我们填写?
之前,让我们考虑一下g
和f
的类型:
g :: a -> b
f :: b -> Int
为清楚起见,我们不妨提一下
f a ~ T (a -> Int)
f b ~ T (b -> Int)
所以我们可以按如下方式填写?
:
instance Contravariant T where
contramap g (T f) = T (f . g)
要变得超级迂腐,您可以将g
重命名为aToB
,将f
重命名为bToInt
。
instance Contravariant T where
contramap aToB (T bToInt) = T (bToInt . aToB)
您可以为Contravariant
撰写T a
个实例的原因可归结为a
在T (a -> Int)
中处于逆变位置的事实。让自己相信T a
不是Functor
的最好方法是尝试(并且失败)自己编写Functor
个实例。
答案 2 :(得分:5)
这是另一个观点。正如liminalisht所示,T
是Contravariant
。关于协变和逆变的类型我们能说些什么呢?
import Data.Void
change1, change1', change2 :: (Functor f, Contravariant f) => f a -> f b
change1 = contramap (const ()) . fmap (const ())
change1' = (() >$) . (() <$)
change2 = fmap absurd . contramap absurd
前两个实现基本相同(change1'
是change1
的优化);他们每个人都使用()
是&#34;终端对象&#34; Hask 。 change2
使用的事实是Void
是&#34;初始对象&#34;。
这些功能中的每一项都会a
替换f a
中b
的所有a
,而不了解b
,f a
或之间的关系他们,其他一切都一样。应该很清楚,这意味着a
并不真正依赖f
。也就是说,T
的参数必须是幻像。对于Sub GreenOrRed()
Dim i As Integer
For i = 2 To i = 27293
If (Cells(i, "S").Value = 0 And Cells(i, "T").Value = 0 And Cells(i, "U").Value = 0) Then
Cells(i, "D").Interior.ColorIndex = 10
Else
Cells(i, "D").Interior.ColorIndex = 9
End If
Next i
End Sub
,情况不,因此它也不能协变。