假设:
class Contravariant (f :: * -> *) where
contramap :: (a -> b) -> f b -> f a
以下代码被拒绝。由于String -> Bool
与Int -> Bool
的对立映射,我期望获得String -> Int
(谓词)。我觉得愚蠢,因为我必须做出一些错误的假设。请帮助我理解错误消息。为什么第二个论点应该与我认为需要的那个不同?
Prelude Control.Lens> contramap length (>0) "Hello"
<interactive>:25:19: error:
• Couldn't match type ‘Bool’ with ‘Int’
Expected type: [Char] -> Int
Actual type: [Char] -> Bool
• In the second argument of ‘contramap’, namely ‘(> 0)’
In the expression: contramap length (> 0) "Hello"
In an equation for ‘it’: it = contramap length (> 0) "Hello"
答案 0 :(得分:9)
Contravariant仅适用于类型构造函数的最后一个参数。您可能需要Profunctor
,它表示在倒数第二个参数中具有逆变性的类型构造函数和在最后一个参数中的协变(如常规函数)。
<Gurkenglas> > lmap length (>0) "hello"
<lambdabot> True
答案 1 :(得分:5)
实际上,你正在寻找无聊的旧协变Functor
实例。
> fmap (>0) length "Hello"
True
在更高级别,您可能正在寻找null
功能。对于许多类型,length
将遍历您传递给它的整个数据结构,而null
通常不会。{/ p>
以下是错误消息的简短说明。第一:
contramap length :: (Contravariant f, Foldable t) => f Int -> f (t a)
(>0) :: (Num a, Ord a) => (->) a Bool
我已经将事情与我希望是一种暗示性的方式结合起来。要将contramap length
应用于(>0)
,我们需要设置f ~ (->) a
和Int ~ Bool
。第二个显然是不可能的,所以编译器抱怨。 (注意:第一个等式只是微妙的不可能;即使你提供的函数返回Int
你也有问题,但编译器还没注意到,因为第二个等式的明显问题胜过它。即:Contravariant
没有(->) a
个实例,但不能!{/ p>