리습 문법에 대해서 전부터 생각하던게 있었는데 밑에 리습 문법 얘기 있길래 생각나서 써봄.


잘 알려져 있는 리습의 대표적인 문법적인 특징은 닫는 괄호가 중첩되는 경우가 많다는 거임.

1 2 3(foo 1 (bar 2 (baz 3)))

처럼.

나는 이게 닫는 괄호의 남용이라고 생각함.


C 문법을 잠깐 보자. C에서 세미콜론으로 구분된 statement들은 얼핏 보면 선형적으로 나열되어 있는 것 같지만 사실은 세미콜론이 있을 때 마다 중첩이 깊어지는 형태임.

1 2 3x = 1; y = 2; z = 3;

이건 아까 리습 코드하고 전혀 다르게 생겼지만, 사실 문법적으로 굉장히 유사함.

왜냐면 변수의 스코프가 아까 리습코드의 괄호로 결정되는 스코프랑 구조가 똑같음.

x는 1, 2, 3번 줄, y는 2, 3번 줄, z는 3번 줄에서 보임. 각 변수는 그 변수가 선언된 위치 부터 코드의 끝 까지를 스코프로 가짐.

리습 코드도 마찬가지임. 괄호가 시작하는 위치는 제각각이지만 끝나는 위치는 전부 동일함.


그럼 문법적으로 봤을 때 앞서 본 리습 예제를 세미콜론으로 써도 충분히 합리적이라는 결론이 나온다.

1 2 3foo 1; bar 2; baz 3;

이렇게 써도 소괄호로 쓴거랑 비슷한 구조로 파싱 가능하다는 소리.


물론 소괄호를 쓰면 임의의 위치에서 스코프를 시작하고 닫을 수 있지만, 세미콜론을 쓰면 무조건 같은 위치에서 일괄적으로 스코프를 닫아야 한다는 문제가 있다. 하지만 이건 필요한 경우에만 명시적으로 괄호를 쓰는걸로 해결 할 수 있음.

1 2 3 4 5 6 7(foo (bar (baz (qux (quux)))) (quuz (corge)))

이런 expression을 생각해보자.


1 2 3 4 5 6 7 8 9 10 11foo { bar; baz; qux; quux; } { quuz; corge; }

이렇게 쓰면 위랑 비슷한 AST로 파싱할 수 있음.

그러니까 세미콜론 만으로는 스코프가 닫히는 위치를 명시할 수 없지만, 그게 필요한 경우에만 괄호를 써주면 표현력에서도 손해를 보지 않는다.

스코프가 시작되는 위치만 구분하고 끝나는 위치는 일괄적으로 블록의 맨 끝으로 하고 싶을 때에는 세미콜론을 사용하고, 시작과 끝을 모두 명시하고 싶을 때에만 괄호를 쓴다고 생각하면 됨.


세미콜론을 쓰는게 소괄호만 쓰는 것에 비해 더 나은 문법일까? 이건 이견이 있을 수 있지만 나는 세미콜론이 낫다고 생각함.

리습 스타일에서 quuz의 스코프는 5번째 줄의 끝에 닫는 괄호가 몇 개 있는지를 봐야 알 수 있는데, 괄호가 뭉쳐있어서 읽기가 매우 불편하다.

대신 6번 라인의 인덴트를 볼 수도 있긴 하지만, 인덴트는 이상하게 하더라도 문법적으로 문제가 없고, 사이에 낀 블록이 길면 인덴트도 읽기 힘듬.

반면에 비슷한걸 블록 및 세미콜론으로 쓰면 문법 구조를 한눈에 파악할 수 있음.


리습에서 괄호는 function application / call 을 표현하는 문법이고 세미콜론은 sequential한 실행을 표현하기 위한 문법이라는 차이가 있긴 하다.

하지만 이미 function application에 세미콜론과 비슷한 문법을 사용한 선례가 있음.


1 2 3x = foo 1 $ bar 2 $ baz 3

바로 하스켈의 $임. 문법적으로 보자면 $는 그냥 "여는 괄호"랑 비슷함. (사실 $는 binary infix operator라서 좌우로 피연산자가 필요하니 똑같진 않다)

$로 쓴 코드를 괄호로 다시 쓰면 다음과 같음.

1x = foo 1 (bar 2 (baz 3))


사실 $ 뿐이 아님. 하스켈에서는 점차 중첩되는 문법 구조를 그냥 선형적으로 작성하는 경우가 많음.

특히 모나드 문법이 가장 주목할만 함. 왜냐면 단순히 코드 스타일을 떠나서 전용 문법까지 만들었거든.

1 2 3 4x = foo >>= a -> bar >>= b -> baz >>= c -> qux a b c

bind operator 를 사용해서 모나딕한 코드를 쓰면 위와 같은 형태가 나옴.

리습 프로그래머는 보통 이것처럼 스코프 중첩이 있을 때 마다 들여쓰기를 하는걸로 알고 있음. (이부분은 내가 리습을 많이 하진 않아서 아닐 수 있음)


하지만 하스켈 프로그래머는 이럴때 들여쓰기를 잘 안함.

1 2 3 4x = foo >>= a -> bar >>= b -> baz >>= c -> qux a b c

그냥 이렇게 쓴다.


1 2 3 4 5x = do a <- foo b <- bar c <- baz qux a b c

do notation을 쓰면 이렇게 됨.

이건 중첩된 형태의 스코프를 가지는 코드를 선형적으로 보이게 만드는 문법을 의도적으로 넣은거임.


내 결론은 이거임.

닫는 괄호가 몰려 있는 expression은 여는 괄호만으로도 표현 하기에 충분함.

여는 괄호만 쓰는 문법을 지원하면 코드를 훨씬 읽기 편하게 만들 수 있음.