如何对函数进行对比?

How to contramap over functions?

鉴于:

class Contravariant (f :: * -> *) where
  contramap :: (a -> b) -> f b -> f a

以下代码被拒绝。我希望通过 String -> Int 上的对映 Int -> Bool 得到 String -> Bool(谓词)。我觉得自己很愚蠢,因为我一定做出了一些错误的假设。请帮助我理解错误信息。为什么第二个参数与我认为需要的不同?

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"

实际上,您正在寻找无聊的旧协变 Functor 实例。

> fmap (>0) length "Hello"
True

在更高层次上,您可能正在寻找 null 函数。对于许多类型,length 将遍历您传递给它的整个数据结构,而 null 通常不会。

这里还有对错误消息的简短解释。第一:

contramap length :: (Contravariant f, Foldable t) => f      Int  -> f (t a)
(>0)             :: (Num a, Ord a) =>                (->) a Bool

我已经按照我希望的建议方式对事物进行了调整。为了将 contramap length 应用到 (>0),我们需要设置 f ~ (->) aInt ~ Bool。第二个显然是不可能的,所以编译器会抱怨。 (N.B。第一个等式只是有点不可能;即使你提供了一个返回 Int 的函数,你也会遇到问题,但编译器还没有注意到,因为第二个等式胜过它。即:(->) a 没有 Contravariant 实例,也不可能!)

逆变仅适用于类型构造函数的最后一个参数。您可能需要 Profunctor,它表示类型构造函数在倒数第二个参数中是逆变的,在最后一个参数中是协变的(如常规 Functor)。

<Gurkenglas> > lmap length (>0) "hello"
<lambdabot>  True