((.) . (.))
왼쪽의 (.)
를 g
, 오른쪽의 (.)
를 f
라고 둡시다.
let g = (.) :: c -> d
f = (.) :: a -> b
in g . f
g . f
가 되려면 f
의 리턴값을 g
가 받아야겠죠. 따라서 c와 b는 같은 타입이 됩니다.
let g = (.) :: b -> d
f = (.) :: a -> b
in g . f
그냥 중위 연산자 (.)
의 타입을 보자면, 오른쪽 인자는 함수고, 왼쪽 인자는 역시 함수인데, 오른쪽 함수의 결과값이 왼쪽의 함수에 들어오는 형태죠. 그래서
(.) :: (y -> z) -> (x -> y) -> (x -> z)
가 됩니다. 같은 말로
(.) :: (y -> z) -> (x -> y) -> x -> z
(.) :: (y -> z) -> ((x -> y) -> (x -> z))
가 되죠. 여기에 함수 g
와 f
를 봅시다.
g :: (gy -> gz) -> ((gx -> gy) -> (gx -> gz))
g :: b -> d
f :: (fy -> fz) -> ((fx -> fy) -> (fx -> fz))
f :: a -> b
type b = (fx -> fy) -> (fx -> fz) -- 실제로 타입 이름엔 첫 글자로 소문자가 올 순 없습니다.
type b = gy -> gz
type gy = fx -> fy
type gz = fx -> fz
대입하자면
g :: ((fx -> fy) -> (fx -> fz)) -> ((gx -> (fx -> fy)) -> (gx -> (fx -> fz)))
f :: (fy -> fz) -> ((fx -> fy) -> (fx -> fz))
g . f :: (fy -> fz) -> ((gx -> (fx -> fy)) -> (gx -> (fx -> fz)))
괄호를 좀 지워봅시다.
g . f :: (fy -> fz) -> ((gx -> (fx -> fy)) -> (gx -> (fx -> fz)))
g . f :: (fy -> fz) -> ((gx -> fx -> fy ) -> (gx -> fx -> fz ))
g . f :: (fy -> fz) -> (gx -> fx -> fy ) -> (gx -> fx -> fz )
g . f :: (fy -> fz) -> (gx -> fx -> fy ) -> gx -> fx -> fz
답은 (b -> c) -> (a -> a1 -> b) -> a -> a1 -> c
였죠?
g . f :: (fy -> fz) -> (gx -> fx -> fy) -> gx -> fx -> fz
g . f :: (b -> c ) -> (a -> a1 -> b ) -> a -> a1 -> c
맞힌 거 같네요.
그냥 이런 함수입니다.
((.) . (.)) g f = \a b -> g (f a b)
한번 써먹어보죠.
ghci> let dot = ((.) . (.))
ghci> sum [3,4,5,6]
18
ghci> take 4 [3..]
[3,4,5,6]
ghci> let sumTake = sum `dot` take
ghci> sumTake 4 [3..]
18
그러니까,
dot g f a b = g (f a b)
에서 ((.).(.))
를 추출해 봅시다. 그 전에 익혀 두시면 좋은 규칙 하나 알려드리죠.
f (g x) = (f . g) x
\x -> f (g x) = f . g
문제로 돌아와서, 맨 끝에 있는 b
를 소거하자면
dot g f a b = g (f a b)
dot g f a b = (g . f a) b
dot g f a = g . f a
이렇게 되겠네요. 다음으로 a
를 소거하고 싶습니다. 어떻게 하면 좋을까요? 여기서부터 돌아올 수 없는 길을 걷게 됩니다. g . f
는 (g .) f
로 다시 쓸 수 있죠?
dot g f a = g . f a
dot g f a = (g .) (f a)
dot g f a = ((g .) . f) a
dot g f = (g .) . f
짠. a
를 소거했습니다. 이제 f
도 소거해봅시다. 뭘 어쩔 거냐면: 중위 연산자를 앞으로 보낼 겁니다.
dot g f = (g .) . f
dot g f = (.) (g .) f
dot g = (.) (g .)
g
도 빼봅시다!
dot g = (.) (g .)
dot g = (.) ((.) g)
dot g = ((.) . (.)) g
dot = ((.) . (.))
짠.