펑터Functor

lionhairdino @lionhairdino@hackers.pub

하스켈에서 펑터를 쓰고 있는 입문자분들과 떠들 내용입니다.

다음처럼 얘기하곤 합니다.

"Maybe Int 타입의 값에서 Int를 꺼내 올 순 없다."

Maybefmap은 패턴 매칭으로 Just 1을 잡아내어 1에 접근하기도 하고, fromJust 등으로 Just가 감싸고 있는 값을 꺼내기도 하는데 이게 무슨 말일까요? 혼자 상상해봤습니다.

올라가면 반드시 내려오는 게 정해진, 경우의 수가 없는 미끄럼틀이 있는데, 내려오는 건 볼 수가 없습니다. 그럼 미끄럼을 내려오는 걸, 미끄럼에 올라 가는 것으로 "표현"할 수 있습니다. 올라 가면 내려오는 이외의 일은 일어나지 않으니까요.

※ 구성원들끼리 어떤 관계를 가지고 있냐를 구조라 부릅니다.

Int 세계에서 이런 구조가 있습니다.

1 ---- (+1) ----> 2

이런 구조를 그대로 살려 Maybe Int같은 구조를 포함하고 있도록 만들고 싶습니다. (펑터는 닮은 것들 끼리 이야기입니다.)

Just 1 ---- (+1) ----> Just 2

Just 1Maybe Int 타입의 "값 자체"는 아닙니다. 1을 받아 Maybe Int타입 값을 생성하는 생성식입니다. 미끄럼틀에 올라가는 것과 비슷합니다. 내려오는 것은 보이지 않으니, 올라가는 것으로 지칭하는 것과 비슷합니다.

Just 1Just 2fmap (+1) 관계에 있도록 하려면, Just 1과 대응되는 원본 1(+1)관계에 있는 2에 대응하는 Just 2를 고르고, 그 둘을 관계짓도록 fmap (+1)을 정의하면 됩니다. 여기서 12Maybe Int에서 빼내온 것이 아닙니다 새로운 세상의 것들과 연관되는 원본들의 포인트를 가져온 것 뿐입니다.

1등만 기억하는 더러운 함수를 만들어 보겠습니다.

func :: Int -> Bool
func 1 = True
func _ = False

일괄적인 어떤 "규칙"을 찾기 보다(분명 사회에는 복잡한 이유가 있겠지만), 여기서는 단순 대응, 매핑, 연관 짓기로 보겠습니다. 마찬가지로 1Just 1은 연관을 지어놨을 뿐, Just 1이 생성한 값의 모양은 일지 일지 뭘로 정했을 지 알 수 없습니다. 아니 알 필요가 없습니다. 우리가 원한 건 원본들의 관계, 즉 구조가 그대로 유지되는 것을 원하니, 그 것만 되고 있으면 됩니다.

fmapMaybe Int 타입 값 안의 Int를 보고 있는 것이 아닙니다.

펑터를 상자로 보고, 상자 안에서 꺼내오는 것으로 인식해도 많은 경우 무리가 없습니다. (대부분의 펑터 설명 그림들이 상자를 은유로 삼습니다.) 그런데, 왜 이렇게 까다롭게 말장난처럼 하냐면, 가끔 상자에 넣어 놨으니, 필요할 때 꺼내면 된다는 메타포가 맞지 않는 경우가 더러 생깁니다.

예를 들면, 상자 메타포가 맞아 떨어지려면, 상자안에 Int를 집어 넣어, 상자를 다루는 함수들을 거친 후 나온 최종 상자에서 Int를 꺼낼 수 있어야 합니다. 하지만, 상자 자체가 사라진 것 같은 결과가 나올 수도 있고, 전혀 Int와 관계 없어 보이는 것들이 나올 수도 있습니다.

※ 값의 성격은 값 모양으로 정해지는 것이 아니라, 값을 다루는 함수들의 동작에 따라 성격이 정해집니다.

없을 수도 있는 수를 꺼낸다

는 말이, 말이 안된다는 걸 알기가 은근 어렵습니다.

6

1 comment

If you have a fediverse account, you can comment on this article from your own instance. Search https://hackers.pub/ap/articles/0197f73c-3ac6-7491-959d-50b9d13e43e2 on your instance and reply to it.

1