Ocaml은 Caml이라는 언어에 객체지향을 섞은 ML family에 속하는 언어이다.
함수형 언어인 여러 언어들이 그렇듯 함수는 first-class value로 값으로 사용된다.
함수가 값으로 사용된다는게 무슨말이냐고 할 수 있는데, 그건 차차 느끼자.
처음부터 파고들면 머리아프다.
Statement와 Expression에 대해
Statement(구문)와 Expression(표현식)에 대해서 잠시 소개할 예정이다.
구문의 정의란 이렇다.
Statement : 실행시 프로그램의 상태전이를 수행하는 언어의 구성요소. ex) int x = 3; 한줄 전부가 구문이다.
메모리 상태를 변경하면 상태 전이가 일어났다고 한다.
메모리에 공간을 잡고 값을 할당하는 짓이 상태전이의 한 형태이다.
또는 이미 할당된 변수의 값을 변경한다던가.
구문은 값을 반환하지 않는다.
또는 값으로 계산되지 않는다.
표현식의 정의는 다음과 같다.
Expression : 실행시 값으로 계산되는 언어의 구성요소
표현식의 실행 결과는 항상 값을 도출한다.
또한 상태전이를 수행하지 않는다.
즉 메모리에 손을 대지 않는다는 뜻.
근데 곰곰히 생각해보니 x++; 같은건 구문일지 표현식일지 궁금해졌다.
상태전이를 수행하고, 값으로 다른 식에 섞여서 사용되지 않으므로 구문일까?
아니면 실행 결과 자체가 값을 반환하기 때문에 표현식일까?
정답은 언어 스펙에서 정의한대로 다르다 같다.
둘다 맞는 말이 될 수 있는데, C나 C++에서는 표현식으로 정의했다.
https://eel.is/c++draft/expr.post#incr
(@ 위 링크는 복붙해서 들어가야한다. 왜인지는 모름..ㅠ)
순수 함수형 언어는 오직 표현식으로만 구성된다.
Ocaml은 순수하지는 않다. 제한된 형태로 메모리 상태를 변경하는 expression이 존재한다고 한다.
물론 다룰 예정은 없다.
위 구문과 표현식과 별개로 모듈 선언 및 값, 타입, 예외에 이름을 붙일 수 있는 definition(정의)가 존재한다.
변수에 대해
Ocaml은 특이하게 변수를 특정 값에 묶인(bound) 식별자로 본다.
이게 뭔말이나면, 변수같이 쓰이는 모든 것들이 c에서의 define구문같이 사용된다는 말이다.
즉 let x = 3 이러면, 컴파일될때 x라고 쓰인 모든 값은 3으로 대체된다.
메모리 공간을 가리키는 것이 아니라, 값에 묶여있다고 본다.
3은 x라고도 불려~ 뭐 이런거다.
값에 묶여있다고 표현했는데, 한번 묶인 변수의 값은 변경이 불가능하다.
let x = 3
let x = 4
let _ = Format.printf "%d\n" x
위와같이 썼으면 Ocaml은 어떻게 받아들일까?
컴파일하면 다음과 같이 오류가 난다.
1 | let x = 3
^
Error (warning 32 [unused-value-declaration]): unused value x.
살짝 감이 잡힌다.
x라는 변수의 값을 교체하는 개념이 아니라
말 그대로 3도 x라고 부르고, 4도 x라고 부른게 돼서, 맨 위의 3은 선언(define)해놓고 안 쓰인 값이라 화를 낸다.
어이가 없지만 감은 잡혔다.
같은 이름의 변수를 여러번 선언하는 경우, 가장 최근에 선언한 변수에만 접근이 가능하다.
이걸 variable shadowing(변수 음영)이라고 한다.
Wildcard
Ocaml에서 wildcard(_)를 사용하는 경우 계산 결과를 버린다는 것을 의미한다.
뭘 굳이 버리기까지.. 하겠냐고 생각할 수도 있다.
위의 코드를 잘 보면 이런 게 있다.
let _ = Format.printf "%d\n" x
Ocaml에서는 '거의 모든 것'이 표현식이라고 했다.
단순히 출력만 하는 저 코드도 표현식이다.
이게 왜 필요할까?
Format.printf "%d\n" 10
Format.printf "%d\n" 23
위 코드는 오류가 난다.
1 | Format.printf "%d\n" 10
^^^^^^
Error: This expression has type ('a -> 'b -> 'c -> 'd, Format.formatter, unit, unit, unit, 'a -> 'b -> 'c -> 'd) CamlinternalFormatBasics.fmt but an expression was expected of type ('a -> 'b -> 'c -> 'd, Format.formatter, unit, unit, unit, unit) CamlinternalFormatBasics.fmt Type 'a -> 'b -> 'c -> 'd is not compatible with type unit
저 오류를 잘 보면 이런 말이다.
포멧으로 정수 하나만 넘긴다고 했는데, 왜 unit타입(@Format.printf는 unit 타입이다.)이 들어왔냐고 화내는거다.
내가 언제 프린트 해주는 표현식을 인자로 줬니?
처음에는 무슨 말인지 이해가 안 돼서 어리둥절했다.
Ocaml은 구문이 없다고 했다.
그말은 무엇이냐면, 줄바꿈이 두 표현식을 구분해주지 않는다는 말이다.
한마디로 저 코드는 그냥
Format.printf "%d\n" 10 Format.printf "%d\n" 23
위 코드랑 같고, 맨 아래 표현식이 함수의 인자로 들어가고 있었다는 말이된다.
와일드 카드를 사용하면 이런 오류로부터 자유로워진다.
let _ = Format.printf "%d\n" 10
let _ = Format.printf "%d\n" 23
위와같이 표현식이 만드는 값을 버려주어야 단순히 실행만 할 수 있다.
Scope에 대해서
Ocaml은 중괄호("{}")를 사용해서 스코프를 만들지 않는다.
대신 let-in 바인딩을 사용한다.
let-in binding : 값에 이름을 붙인 후 세부 expression을 수행하는 expression
Format.printf "%d\n" (
let x = 3 in
let x = x + x in
x
)
위 코드에서는 let-in 바인딩을 사용한다.
맨 위 출력 표현식은 인자로 let-in 바인딩되는 값을 사용한다.
let-in 바인딩이 표현식이라고 했으니 당연히 반환값이 있다.
괄호를 친 이유는 먼저 계산한다는 뜻이다. 괄호가 없으면 인자로 이상한게 들어가서 컴파일 오류가 발생한다.
이제 맨 위 바인딩부터 살펴보자.
먼저 3을 x와 바인딩했다.
다음 in을 통해 스코프를 만든다.
이제 그 이후에 쓰이는 값들은 x가 모두 3으로 치환된다.
두번째 바인딩은 맨 위에 바인딩된 x를 사용하여 새로운 값(6)을 x와 바인딩한다.
in 이후에서는 맨 위의 x(값이 3)은 아까 말했듯 variable shadowing이 발생하여 x는 더이상 3이 아니라 6으로 치환된다.
맨 마지막에 x를 반환한다.
따라서 출력값이 6이 된다.
Sequencing
Sequencing은 연속적인 unit expression의 계산을 수행할때 사용한다.
다른 언어에서 쓰던 방식과 다르다는것을 인지하자.
연속된 '표현식'을 사용할때 사용하고, 게다가 unit이 반환되는 표현식이다.
몇가지 규칙이 있다.
1. 세미콜론은 연속적으로 실행할 expression을 연결할 때만 사용하여야 하고, 맨 마지막에는 붙이지 않는다.
2. 마지막 expression을 제외한 모든 expression의 계산 결과는 반드시 unit이어야 한다.
Format.printf "hi1\n";
Format.printf "hi2\n";
let x = 3 in x
따라서 위와같이 작성이 가능하다.
함수
Ocaml의 대표 선수 함수다.
맨 위에서 언급했지만, first-class value로 함수 자체가 표현식이자 값이다.
사용방식은 코드를 보며 이해해보자.
let x = fun a b -> a + b in
Format.printf "%d\n" (x 1 2)
fun 다음에 인자를 적고, "->" 다음에 표현식을 넣어준다.
이름을 꼭 왼쪽에 적고 fun으로 익명 함수를 만들어 바인딩해주는게 짜증난다고 생각할 수도 있다.
내가 그랬다.
let x a b = a + b in
Format.printf "%d\n" (x 3 4)
위와 같이 사용할 수도 있다.
함수와 바인딩될 식별자를 같이 적어주는 식으로 일종에 문법적 설탕(syntactic sugar)이다.
'언어 > Ocaml' 카테고리의 다른 글
[Ocaml] Pattern matching (0) | 2023.04.06 |
---|---|
[Ocaml] 함수의 타입에 대해 (0) | 2023.04.05 |