함수형 시작과 아마도 끝

Posted on May 7, 2021

요리팀에 케이크를 만들어 달라 부탁하려 합니다.

절차형(명령형)

밀가루를 가져온다.
반죽 요리사가 반죽을 한다. 
반죽을 테이블에 올려 둔다.
반죽을 가져와 굽기 요리사가 굽는다.
구워진 빵을 테이블에 올려 둔다.
빵을 가져와 크림 요리사가 크림을 얹는다.
케이크를 테이블에 올려 둔다.

어차피 필요한 작업은 다를 수 없습니다. 절차형이건 함수형이건 반죽,굽기,크림얹기를 해야 케이크가 완성됩니다. 차이점은 요리팀에 준비를 시키는, 명령을 내리는 순서가 좀 다릅니다.

함수부터 먼저 모여

함수형

반죽 요리사 준비
굽기 요리사 준비
크림 요리사 준비
모두 준비 됐으면 밀가루를 가져 온다.

함수형은 제일 먼저 요리사(함수)들을 주욱 엮어 두고, 밀가루를 딱 넣는 순간 휘리릭 케이크가 나옵니다.

이 말을 Reader 모나드에 적용하면,

제일 먼저 Reader 액션들을 바인드로 주욱 엮어 두고, env 값을 딱 넣는 순간 휘리릭 실행되어 결과가 나옵니다.

프로그램의 일부 코드만 이렇게 되어 있는게 아닙니다. 하스켈 프로그램 전체가 IO모나드로 엮은 상태로 되어 있고, Realworld값을 넣어주는 순간 프로그램이 실행됩니다.

그래서, 요리사의 가장 중요한 덕목은 다른 요리사와 바로 대화composition하는 능력입니다. 그래야, 요리팀에 들어갈 수 있습니다. 하스켈의 낯선 관용구, 패턴, 스타일들의 대부분 목적은 함수를 엮기 위한 겁니다.

보통 함수형 사고에 관한 얘기를 꺼낼때는 리스트 같은 스트림에 fmap, filter, foldr 같은 함수들을 적용하는 구조를 먼저 얘기합니다. 이런 구체적 사례 이전에, 함수형 프로그래밍은 함수를 엮어서 문제를 해결한다는 큰 형태부터 알고 들어가면 어떨까 합니다. 아예 값이라는 개념을 지우고 시작해서 함수들을 엮다 보면, 함수형의 에센스 같은 함수들이 자연스럽게 느껴지기도 합니다.

저 같은 경우는 모나드의 bind 동작을 아무리 자세히 설명한 자료를 봐도 “특정 형태의 함수를 엮기 위해”란 목적을 알기 전까지는 지식을 좇아가는데 어려움을 느꼈었습니다. 문제들의 해결책이 아주 터무니 없는 지식, 구조, 방법들인 경우는 거의 없습니다. 먼저 목적을 알면, 스스로 생각해 볼 기회가 생겨 더 빠르게 익숙해질 수 있습니다.

함수를 엮는 스타일이 나왔을까요? 하스켈 언어의 근간은 상태가 존재하지 않는다입니다. 상태가 없으니, 함수들의 작업 결과를 유지하는 방법은 바로 이어지는 함수의 입력으로 넘겨주는 방법밖에 없습니다. 어떻게든 필요한 정보, 상태는 촘촘히 엮여진 함수들을 끊임없이 돌아다니게 해야 합니다.

상태가 없는 구조를 선택했을까요? 상태가 없다는 말은, 생각을 물고 물어 가다보면, 함수에 같은 입력이 들어오면 어떤 경우에도 다른 출력을 내놓지 않는다는 것과 같다는 생각에 도달합니다. (side effect가 없다고 표현하기도 하고, 참조 투명성이라 표현하기도 합니다.) 함수 하나 하나가 모두 독립적으로 견고한 하나의 블럭(원자같은..) 역할을 합니다. 함수가 예상치 못한 동작을 하는 경우가 없다면, 함수 하나가 에러가 날 이유도 없어집니다. 이런 확고한 구조(믿음?)가 있다면, 디버깅을 생각하는 방식이 달라집니다.

명령형과 함수형을 나누는 중요한 개념으로 side effect 처리를 들 수 있습니다. 까다롭게 나누어 보면 아래 두 가지 뜻이 보입니다.

  1. 예를 들어 덧셈을 하는 함수인데, 보조적으로 덧셈을 표시하는 문자열을 로그에 추가하는 작업이 있다면, 개념적으론 이 작업 자체가 side effect입니다. 덧셈 작업과 직접 연관이 없는 작업이란 의미입니다. 덧셈 작업은 오직 “덧셈”만 해야 순수하다 말합니다.
    “그런데, 하스켈 함수는 side effect가 없다고 하지 않았나요?”
    엄밀히 말하면 순수 함수를 써서 side effect와 같은 결과가 나오는 작업을 만드니, side effect “개념” 자체가 없다란 말은 의미상 맞지 않습니다.
    “side effect를 순수 함수로 구현해”가 맞는 말입니다.
    수학과 다르게 프로그램은 온 갖 side effect가 섞여 완성됩니다.

  2. 매개 변수(컨텍스트 포함) 이외의 통로를 이용해 외부와 영향을 주고 받는 걸 side effect라 말합니다.

하스켈 커뮤니티에선 두 가지 뜻 모두 쓰이는 것으로 보입니다.

※ effect와 side effect
partiality, nondeterminism, side-effect, exceptions, interactive input/ouput을 effect라고 말합니다. 전 코딩할 때는 a에서 f a로 갔다가 다시 a로 돌아올 때 잃어버리는 정보를 effect라고 해석하고 있는데, 이렇게 해석하는 문서는 아직 못봤으니 정확한 정의는 아닌 것 같습니다. effect중 mutation이 일어나는 걸 side-effect라고 하는 것 같습니다. 정확한 정의를 보게되면 추가하도록 하겠습니다.

보통 부수 효과라 번역하는데, 느낌이 잘 사는 번역은 아닌 것 같습니다. 지금껏 다른데서 부수 효과란 말을 쓸 때는, 기대하지 않았는데 거둬들이는 효과로 긍정의 판단이 섞여 있을 때 썼습니다. 직역이 아닌 속 뜻을 본다면, 첫 번째 의미는 ”비순수 작업, 부가적 작업, 부차적 작업, 두 번째 의미는 외부 작용쯤 되지 않을까요?

※ 타입 체계 입장에서는 mutation이 일어나는 상황 자체가 부정적인 뉘앙스로 볼 수 있다고 합니다. 그렇다면 부수 효과가 적절한 번역일 것 같습니다.

“side effect를 순수 함수로 해결해” -> “비순수 작업을 순수 함수로 해결해”
“side effect가 없다.” -> “외부 작용이 없다.”

아직, 어느 하나로 통일할만한 용어가 떠오르지 않습니다.

람다 대수

람다 대수 표현은 작업 진행을 함수가 함수를 품는 걸로만 표현합니다. 하스켈은 람다 대수를 그대로 옮겨 놓은 것이라 보면 되는데, 처음 람다 대수를 고안한 알론조 처치 수학자가 왜 람다 대수를 떠올렸는지는 간단한 교양 수준으로 접근할 수 있는 자료는 없어 보입니다. 람다 대수의 시작은 1936년이었고, 프로그래밍과의 관계를 알게된 건 1960년대라 합니다. 처음부터 기계적 프로세스를 고려해서 나온 이론은 아니었는데, 어디서 연결점을 찾았을지 궁금하긴 합니다. 참고 - 상태 개념 포스트

대수

보통 어떤 논리나 구조를 정확한 언어로 설명하려고 할 때, 수학자들은 새로운 대수 체계를 만들곤 합니다. 대수란 모호함이 없도록 정제된 언어같은 겁니다. - 인간이 사용하는 일상 언어는 모호함이 존재합니다. 위에 얘기했던 외부 상황, 상태에 의존하는 용어가 대부분이다 보니, 모든 환경context을 다 얘기할 수 없다면 모호할 수 밖에 없습니다. 누군가 영상 5도라 날씨가 쌀쌀하다 말한다면, 북극에 사는 사람은 이해할 수 없는 말일 수도 있습니다. 상황을 모두 얘기한다면 그나마 오해의 여지를 줄여 나갈 순 있지만, 인간의 일상 언어만으론 오해 가능성을 아예 없애긴 어렵습니다. 그래서, 일상 용어의 모호함을 피하기 위해, 특정 구조에서 항상 만족하는 절대 조건들을 쌓아가며 대수 체계를 만들어갑니다. 대수란 언어를 이용해 확고한 명제를 쌓아 올려가며 논리, 이론을 증명합니다. 1 + 1 은 항상 2입니다. - 람다 대수가 증명하려던 논리를 알아야 궁금증이 해결 될텐데, 여기서 멈춰야 할 것 같습니다.

하스켈을 공부하다 보면 아카데미와 적당히 선을 그어야겠다는 생각이 종 종 듭니다. 처음 보는 함수나 패턴을 좇아 가다보면, 논문에 논문으로 한 없이 들어갑니다. 이해하면 당연히 좋을 거란 생각이 들지만 무한정 원리에 시간을 쏟기에는 다른 알아야 될 게 많습니다. 저는 주로, 아이디어만 수긍이가면 빠져 나오려고 노력합니다. - 물리를 공부하다 만유인력이 왜 생기는지, 파동이 무언지 궁금해지면 정말 난처한 상황에 들어갑니다! (이런데는 많은 지식이 쌓인 후에 다음 스텝으로 만나야 합니다.)

함수 연결? 합성? 엮음? 묶음?

말이 잠깐 다른데로 가는 걸 다시 붙잡으면, 그래서 함수형의 시작과 끝은?
바로 composition입니다. 함수 자체보다 함수가 어떻게 다른 함수와 연결 되는지가 더 관심사입니다.

여기 포스트들은 합성, 연결보다는 엮는다는 표현을 많이 씁니다. 함수의 연결이 단순히 사슬 연결하는 메타포가 아니라, 클로저가 살아있어 감싸고 감싸는 모양이라 연결이라는 말 이상의 느낌이 필요해서입니다. 합성이란 말은 순서 없이 섞이는 느낌이 들기도 하는데, 딱 맞는 용어가 무얼까요?

이렇게 얘기하는게 이미 어느 정도 알고나서 들으니 의미 있어 보이는 건지, 처음부터 이렇게 얘기만 해도 의미를 잡아낼 수 있을지는 잘 모르겠습니다.

2022.5.13 이 것도 지금 보니 굉장히 오만한 제목을 달았네요.

Github 계정이 없는 분은 메일로 보내주세요. lionhairdino at gmail.com