클로저는 pure하지 않을때 더 빛을 발하는 기법이 아닐까 생각됩니다.
일단 쓸데없는 어그로를 덜 끌기 위해 딱국 닉네임은 뺏구요, 댓글에서 누가 왜 자꾸 딱국으로 오냐고 하는게 있어서 의견을 반영했습니다.
어차피 제가 글을쓰면 딱국인거 다 알아볼거라고 생각하긴 하지만요.
하스켈을 공부하면서 클로저라는 개념은 전혀 소개받지 못했었는데요,
하스켈 클로저로 검색해보니까
f x = \y -> x + y 같은 함수들이 나오더라구요.
이런 의미의 클로저는 람다대수가 성립하기 위한 전제조건입니다.
불변 변수를 캡처하는 경우죠.
하지만 제가 이제부터 말하려는 클로저는 "상태"를 캡처한 경우를 의미합니다.
상태를 캡처한 클로저의 예시는
오카멜로 적어보겠습니다. 다음과 같습니다.
let closure () =
let state = ref 0 in
{state_read = (fun () -> !state);
state_write = (fun x -> state := x) }
closure () 를 실행할때마다 새로운 환경에서 새로운 state가 생성되고,
closure () 의 반환값인 레코드(자바스크립트의 객체처럼 받아들이셔도 됨) 의 state_read 를 사용할때마다 값을 읽어올 수 있고
state_write를 쓸떄마다 값을 변경할 수 있습니다.
state_wrtie로 값을 변경하고 state_read로 값을 읽으면 반환값이 달라지므로,
이 함수 둘은 전부 pure하지 않습니다.
하스켈에서 이런 클로저를 만들려면
unsafePerformIO 를 써서 IO 모나드 컨텍스트 안에 있는 값을 빼와야합니다.
IO (IORef a) 에서 IORef 를 빼낸 후, 그걸 클로저 안에 집어넣던지
아니면 IO (IORef a)를 통해 IO (클로저) 를 생성한 후, IO (클로저) 안에서 클로저를 빼내던지간에 unsafePerformIO를 통한 값 빼내오기 전략이 필수적입니다.
(후자 경우 클로저 내부의 IORef가 Share될수 있도록 신경 써줘야합니다. 타입이 폴리몰픽한 경우를 예시로, 클로저를 빼왔는데도 내부 캡처 변수를 매번 재생성하는 경우가 있었습니다.)
이 경우는 의도적으로 순수성을 깨뜨리는 경우이기 때문에, unsafe의 사용 이 하스켈스럽다의 정의가 되지 못할지라도,
위와 같이 상태를 캡처하는 클로저가 하스켈스러운 코드라고 보기엔 확실히 무리가 있다고 판단했습니다.
얘기가 좀 많이 길어지고 장황해졌는데요, 여기서 요약하고 가겠습니다.
변수를 캡처하는 클로저.
변수가 불변값이라면 하스켈에서도 클로저는 있고, 하스켈의 중요한 철학이다.
하지만 내가 강력하다고 생각하는 클로저의 활용법은 counter 변수 처럼, 상태를 외부에서 변경 가능한 경우를 의미할 때가 많다.
이러한 코드는 순수함수가 아니며, 따라서 하스켈스럽다고 보기 어렵다.
이러한 측면이 제가 오카멜을 하스켈보다 더 선호하는 이유가 됩니다.
오카멜의 구현력이 확실히 하스켈보다 더 좋다고 생각해요.
하스켈로는 카운터를 함유하는 클로저를 만들수도 없고, 만들어서도 안되니까요.
하지만, 복잡한 멀티스레딩 코딩을 하는 경우에는 하스켈처럼 구현력을 제한하고 안전성에 초점을 맞추는 것이 좋다고 생각이 바뀌게 되겠죠??
근데 복잡한 멀티스레딩 코딩을 할 경우에 러스트가 좋은 대안이 되지 않을까요??
이 글은 어디까지나
오카멜 공부를 하면서
오카멜이 클로저를 강력하게 사용하는 모습을 보고, 감명받아서 쓴 글입니다.
솔직히 하스켈 입장에서 가변 클로저를 어떻게 바라볼지도 굉장히 궁금하구요
넹
니가 딱국이든 아니든 1도 관심 없고, 기초적인 글쓰기 연습좀 해라. 용건만 간단히 말해라