contravariant functor

Jason Kim·2020년 8월 29일
1

contravariant functors reverse the direction of composition. - Wikipedia

covariant functor
F(f∘g)=F(f)∘F(g)

contravariant functor
F(f∘g)=F(g)∘F(f)

covariant map with ((->) r)
(a -> b) -> (f a -> f b)
(a -> b) -> ((->) r a) -> ((->) r b))
(a -> b) -> (r -> a) -> (r -> b)

contravariant map with (_ -> c)
(b -> a) -> (f a -> f b)
(b -> a) -> (a -> c) -> (b -> c)

(a0 -> a1) 함수가 있을때 합성을 통해 함수의 출력을 변경하는 함수를 만들 수 있다.
(.) :: (a1 -> z) -> (a0 -> a1) -> (a0 -> z)
((->) a0)를 functor로 본다면 (a1 -> z) 함수에 ((->) a0)의 fmap을 적용해서 lifting 하는것과 함수의 합성은 동일하다.
fmap :: (a1 -> z) -> (f a1) -> (f z)

그리고 합성의 방향을 바꾼다면 a0가 아닌 타입의 값을 a0로 변환하여 이 함수를 실행시킬 수 있는 함수를 만들 수 있다.
flippedCompose :: (r -> a0) -> (a0 -> a1) -> (r -> a1)
(_ -> a1)을 functor로 만들어보면 fmap으로는 이걸 할 수 없다. fmap에 (_ -> a1)을 적용해보면 이렇게 되기 때문이다.
fmap :: (r -> a0) -> (r -> a1) -> (a0 -> a1)
이때 필요한게 contravariant functor 이다. fmap과 비교를 위해 나란히 써봤다.

fmap      :: (a -> b)  -> f a -> f b
contraMap :: (a -> b)  -> f a <- f b
contraMap :: (a -> b)  -> f b -> f a

(a0 -> a1) 함수를 중심으로 생각을 해보면 compose/fmap은 함수 실행 후 출력을 변경하는 함수를 지정할 수 있는 반면, pipe/contraMap은 함수가 실행되기 전 입력값을 a0 타입으로 조정하는데 사용된다.

함수 타입에서 반환 타입은 공변적(covariant) 이고, 인자 타입은 반공변적(contravariant) 이라는것을 생각하면 자연스럽게 이해가 될 것이다.

하스켈에서는

instance Contravariant (_ -> z) where
  ...

위와 같이 사용할 수는 없기 때문에 Op, Predicate와 같이 Contravariant를 구현하고 있는 특화된 타입이 존재한다.

더 읽어보기

https://math.stackexchange.com/questions/702551/variance-of-functor
https://edykim.com/ko/post/what-is-coercion-and-anticommunism/

0개의 댓글