Haskell 如何对函数进行反向映射?

Haskell 如何对函数进行反向映射?,haskell,contravariance,Haskell,Contravariance,鉴于: 以下代码被拒绝。我希望得到String->Bool(一个谓词),这是Int->Bool对String->Int进行反向映射的结果。我觉得自己很愚蠢,因为我一定是做出了一些错误的假设。请帮助我理解错误消息。为什么第二个论点与我认为需要的论点不同 class Contravariant (f :: * -> *) where contramap :: (a -> b) -> f b -> f a Prelude Control.Lens>对映长度(>0)“你好”

鉴于:

以下代码被拒绝。我希望得到
String->Bool
(一个谓词),这是
Int->Bool
String->Int
进行反向映射的结果。我觉得自己很愚蠢,因为我一定是做出了一些错误的假设。请帮助我理解错误消息。为什么第二个论点与我认为需要的论点不同

class Contravariant (f :: * -> *) where
  contramap :: (a -> b) -> f b -> f a
Prelude Control.Lens>对映长度(>0)“你好”
:25:19:错误:
•无法将类型“Bool”与“Int”匹配
预期类型:[Char]->Int
实际类型:[Char]->Bool
•在“contramap”的第二个参数中,即“(>0)”
在表达式中:contramap length(>0)“Hello”
在“it”的等式中:it=contracmap length(>0)“Hello”

实际上,您正在寻找无聊的旧协变函数
函子
实例

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

下面是错误消息的简短解释。第一:

> fmap (>0) length "Hello"
True

我以一种我希望具有启发性的方式来协调事情。为了将
contracmap length
应用于
(>0)
,我们需要设置
f-a
Int~Bool
。第二个显然是不可能的,因此编译器抱怨道。(注意:第一个方程只是微妙地不可能;即使你提供了一个返回
Int
的函数,你也会有问题,但是编译器还没有注意到,因为第二个方程的明显问题压倒了它。也就是说:
(>)a
没有
逆变
实例,而且不可能!)

逆变仅适用于类型构造函数的最后一个参数。您可能需要
Profunctor
,它表示类型构造函数,这些构造函数在倒数第二个参数中是逆变的,在最后一个参数中是协变的(类似于正则函子)

contramap length :: (Contravariant f, Foldable t) => f      Int  -> f (t a)
(>0)             :: (Num a, Ord a) =>                (->) a Bool
>lmap长度(>0)“你好”
真的

什么是
逆变((->)a)
实例?@Alec:没有,因为参数用在正位置。@Alec-Ah。欢迎。:)当然是
(.)
fmap(>0)长度=(>0)。经过深思熟虑,我想我更喜欢这个答案!它强调了提问者可能具有的相同直觉,并解决了
反变的第一类论点/第二类论点的问题,这可能是提问者头脑中发生的实际误解。我认为GHC会以某种方式推断出一个具体的
Bool
。但它在类型级别上仍然是一个“自由变量”。换句话说,我以为我在使用
newtype谓词a=a->Bool
,我认为它实际上是反变的。我的
对映长度(谓词(>0))
现在进行类型检查。@sevo它是关于(类型)参数位置的,而不是关于变量与非变量的关系。GHC确实推断出了具体的
Bool
ness。还考虑<代码> NeXType谓词B A=谓词(A---B),它仍然将是一个<代码>反变量实例。
<Gurkenglas> > lmap length (>0) "hello"
<lambdabot>  True