Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to contramap over functions?

Given:

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

The following code is rejected. I'm expecting to get String -> Bool (a predicate) as a result of contra-mapping Int -> Bool over String -> Int. I feel stupid as I must be making some wrong assumptions. Please help me in understanding the error message. Why is the second argument expected to be different than the one I think I need?

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"
like image 734
sevo Avatar asked Dec 08 '22 21:12

sevo


2 Answers

Contravariant only works on the last argument of a type constructor. You might want Profunctor, which denotes type constructors that are contravariant in the second to last argument and covariant (like a regular Functor) in the last one.

<Gurkenglas> > lmap length (>0) "hello"
<lambdabot>  True
like image 66
Gurkenglas Avatar answered Dec 10 '22 10:12

Gurkenglas


Actually, you're looking for the boring old covariant Functor instance.

> fmap (>0) length "Hello"
True

At an even higher level, you may be looking for the null function. For many types, length will traverse the entire data structure you pass to it, whereas null generally will not.

Here is a short explanation of the error message, as well. First:

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

I have aligned things in what I hope is a suggestive way. In order to apply contramap length to (>0), we would need to set f ~ (->) a and Int ~ Bool. The second is clearly impossible, so the compiler complains. (N.B. The first equation is only subtly impossible; even if you supplied a function which returned an Int you'd have a problem, but the compiler doesn't notice yet because the obvious problem with the second equation trumps it. Namely: there is no Contravariant instance for (->) a, and can't be!)

like image 36
Daniel Wagner Avatar answered Dec 10 '22 10:12

Daniel Wagner