DEV Community

Ingun 전인건
Ingun 전인건

Posted on • Edited on

함수 합성 함수의 합성 - (.).(.)

코도메인(codomain)과 도메인(domain)이 같은 두 함수의 합성(composition)은 익숙하실거에요.

f:BCg:ABh=fgh:AC f : B \rightarrow C \newline g : A \rightarrow B \newline h = f \circ g \newline h: A \rightarrow C

근데 함수 합성 자체도 함수죠? 그렇다면 함수 합성 함수를 합성하면 어떤함수가 될까요?

()()=? (\circ) \circ (\circ) = ?

결론부터 말하자면 일항함수와 이항함수를 합성할 수 있는 새로운 합성함수가 탄생해요. 즉

f:CDg:A×BC f: C \rightarrow D \newline g: A \times B \rightarrow C

일때 hh 를 다음과 같이 정의하면

h=f(()())g h = f \left( (\circ) \circ (\circ) \right) g

hh 는 다음과같아요

h:A×BDh(a,b)=f(g(a,b)) h : A \times B \rightarrow D \newline h(a,b) = f(g(a,b))

한발 더 나아가서 함수합성함수 세개를 합성한다면?!

f:DEg:A×B×CDh:A×B×CEh=f(()()())gh(a,b,c)=f(g(a,b,c)) f : D \rightarrow E \newline g : A \times B \times C \rightarrow D \newline h : A \times B \times C \rightarrow E \newline h = f \left( (\circ) \circ (\circ) \circ (\circ) \right) g \newline h(a,b,c) = f(g(a,b,c))

일항 함수와 삼항 함수를 합성할 수 있는 새로운 합성자가 생기죠. 즉 도메인의 차수가 하나 더 늘어나는거에요.

왜그런지 이해하기 위한 가장 쉬운 방법으로는 직접 증명 해보는 방법이 있어요. 대략적으로 증명하자면 다음과 같아요. (이 글의 목적은 직접 증명을 설명하는게 아니므로 친절한 설명은 생략할게요)

합성은 다음과 같은 모양이므로.

:(βγ)×(αβ)(αγ) \circ: (\beta \rightarrow \gamma) \times (\alpha \rightarrow \beta) \rightarrow (\alpha \rightarrow \gamma)

여기서 파라메터 둘 다 합성함수 이므로 필연적으로 α,β,γ\alpha, \beta, \gamma 도 다음과 같은 모양을 띄게 된다.

α:yzβ:(xy)(xz)γ:(a(xy))(a(xz)) \alpha : y \rightarrow z \newline \beta : (x \rightarrow y) \rightarrow (x \rightarrow z) \newline \gamma : (a \rightarrow (x \rightarrow y)) \rightarrow (a \rightarrow (x \rightarrow z))

그러므로 다음과같이 일항 함수와 이항 함수의 합성함수의 모양을 띄게 된다.

αγ=(yz)(axy)(axz) \alpha \rightarrow \gamma = (y \rightarrow z) \rightarrow (a \rightarrow x \rightarrow y) \rightarrow (a \rightarrow x \rightarrow z)

어렵지 않게 결론에 도달할 수 있을거에요.

하지만 이 방법은 단순히 명제의 참거짓 여부만 판단할 수 있을뿐 정작 라는 물음에는 답해주지 않죠. 함수 합성은 어떤 성질이 있길래 둘을 합성하면 이런 마법같은 효과가 있는걸까요? 만약 홈펑터 (Hom functor) 라는 개념을 알고있다면 더 나은 설명이 가능해요.

카테고리 이론의 시점에서 함수 합성은 홈펑터에요. 임의의 두 함수의 합성을 홈펑터로 나타내본다면 다음과 같아요.

hom(x,):(yz)(yxzx) \circ_{hom(x,-)} : (y \rightarrow z) \rightarrow (y^x \rightarrow z^x)

Alt Text

여기서 xyx^y yxy \rightarrow x 와 같아요.

그리고 우리가 원하는 더블 합성은 다음과 같죠.

hom(x,)hom(a,):(yz)(yxazxa) \circ_{hom(x,-)} \circ \circ_{hom(a,-)} : (y \rightarrow z) \rightarrow (y^{xa} \rightarrow z^{xa})

Alt Text

f:yzf: y\rightarrow z g:x×ayg: x\times a \rightarrow y 만 있으면 더블 펑터 합성을 이용해서 h:x×azh: x\times a \rightarrow z 을 만들 수 있게 되는거죠.

하스켈에서 2차원 벡터의 길이를 구하는 코드를 예로 들어볼게요. 보통 벡터를 다루는 라이브러리들은 꼭 필요한 상황이 아닌이상은 퍼포먼스를 위해 벡터의 길이보다는 제곱근을 적용하기 전의 벡터길이를 사용하는것을 권장해요. 여기서도 제곱근 이전 길이를 구하는 함수 squaredMagnitude함수를 구현한 후, 실제 길이를 구하는 magnitude함수를 위에서 논한 방법을 이용해서 제곱근 함수와 squaredMagnitude를 합성해서 구현을 해 볼게요.

(.*) :: (c -> d) -> (a -> b -> c) -> (a -> b -> d)
(.*) = (.) . (.)

squaredMagnitude :: Double -> Double -> Double
squaredMagnitude x y = x^2 + y^2

magnitude = sqrt .* squaredMagnitude

main :: IO ()
main = do
  print $ squaredMagnitude 3 4
  print $ magnitude 3 4
Enter fullscreen mode Exit fullscreen mode

결과는 다음과 같아요

25.0
5.0
Enter fullscreen mode Exit fullscreen mode

Top comments (1)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.