전부터 궁금했던 게 있었어.
"모든 모나드는 어플리커티브다. 모든 어플리커티브는 펑터다."
그렇다면 비슷한 성격의 타입클래스가 왜 세 개나 있어야 할까?
이에 대한 대답을 어느 정도 알게된 것 같아 정리해본다.
1. 서브클래스가 서브셋을 의미하지 않는다.
저 위의 문장을 클래스 상속 구도로 나타내면
Functor
Applicative: Functor
Monad: Applicative
이렇게 되는데, 가장 유용하고 기능이 많은 것은 모나드임.
즉, 할 수 있는 능력으로 구분하면, 모나드가 가장 강력하고, 어플리커티브는 그 다음, 펑터는 마지막이 되는거지.
서브클래스는 서브셋이 아니라 오히려 수퍼셋에 가깝다. 서브라는 접두사를 공유하지만 포함 관계는 반대.
2. 수학의 함자, 적용성 함자, 단형 함자, 단일체 등등은 몰라도 된다.
정말 알 필요 없음. 내가 공부할 때 곁가지로 자주 빠지는 유형이라 시간대비 성과가 좋지 않은데..
그런 나도 이 쪽 수학은 감히 빠질 생각을 못 하겠더라. 모노이드 하나만 해도 엄청난 양이고 내용도 도대체가 알아들을 수 없는 말들이라서 깔끔하게 접어두기로 했다. cs 전공자라, 그래도 수학 좀 안다고 생각했는데, 완전 깨갱함.
다행히 몰라도 코드 짜는데는 전혀 지장이 없음.
3. 한 눈에 보는 펑터-어플리커티브-모나드
|
Functor |
Applicative |
Monad |
map (a -> b) -> f a -> f b |
fmap |
<$> |
liftM |
wrap a -> f a |
없음 |
pure |
return |
wrapped map f (a -> b) -> f a -> f b |
없음 |
<*> |
ap |
bind f a -> (a -> f b) -> f b |
없음 |
없음 |
>>= |
flatten f (f a) -> f a |
없음 |
없음 |
join |
모나드와 어플리커티브는 래퍼 클래스라고 생각하면 됨.
펑터는 그 둘을 포함하는 가장 추상화된 인터페이스라고 보면 되고.
래퍼와 래핑이라는 것은 어떤 컨텍스트에 담는 것을 말하는데, 위의 표에서 a와 f a의 차이를 보면 돼.
a가 일반 값 normal value 이고, f a는 이러한 일반 값을 컨텍스트에 담은 값 fancy value 을 의미한다.
셋의 차이는 다룰 수 있는 함수에서 차이가 나.
펑터는 map만 가능함. 즉 함수 자체는 일반 값에 관한 함수만 받아.
어플리커티브는 펑터의 기능에 추가로, 함수 전체가 래핑된 경우도 처리할 수 있어.
모나드는 어플리커티브의 기능은 물론, 일반 값에서 팬시 값으로 정의된 함수인 경우도 처리할 수 있지.
모나드의 저 말, 일반 값에서 팬시 값으로 정의된 함수가 바로 순수와 비순수를 연결하는 부분이야.
순수성을 위해서 모나드 구조를 도입한 이유를 이해할 수 있는 부분이지.
모두들 재밌는 하스켈 배우자.
람다 후 아크바르!
ㅊㅊ
lambdāhu Hamkbar!