Values — let로 값을 바인딩하기

Values — let로 값을 바인딩하기

F#에서는 값을 만드는 일이 아주 자주, 그리고 아주 중요하게 등장해요. 다른 언어에서는 변수를 선언(declare)한다고 말하지만, F#에서는 이름과 정의를 연결한다는 뜻으로 **바인딩(binding)**이라는 말을 써요. 그 중심에는 let 키워드가 있어요. 이 글에서는 let으로 값을 만들고, F#이 왜 불변(immutable) 값을 기본으로 삼는지, 그리고 꼭 필요할 때 값의 묶음을 어떻게 푸는지까지 차근차근 살펴볼게요.

출처: https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/values/

본문

값 바인딩하기 (Binding a Value)

바인딩이라는 말은 이름과 정의를 서로 연결한다는 뜻이에요. let 키워드가 바로 그 역할을 해요. 실제 예시를 볼게요.

let a = 1
let b = 100u
let str = "text"

// A function value binding.

let f x = x + 1

값의 타입은 정의에서 자연스럽게 추론돼요. 정수나 부동 소수점 같은 기본 타입이라면 리터럴의 종류가 타입을 결정해요. 위 예시에서 컴파일러는 b의 타입을 unsigned int로, a의 타입을 int로 추론해요. 함수 값의 타입은 함수 본문의 반환값으로 정해지죠. 함수 값 타입에 대해 더 자세히 알고 싶다면 Functions를, 리터럴 타입에 대해 더 알고 싶다면 Literals를 살펴봐요.

참고로 F# 컴파일러는 기본적으로 사용되지 않는 바인딩에 대해 경고를 내보내지 않아요. 이런 메시지를 받고 싶다면 프로젝트 파일이나 컴파일러 호출 시점에 경고 1182를 켜면 돼요(--warnon 참고, Compiler Options).

왜 불변인가? (Why Immutable?)

불변 값은 프로그램이 실행되는 내내 절대 바뀌지 않는 값을 말해요. C++, Visual Basic, C# 같은 언어에 익숙하다면, F#이 실행 중에 새 값을 다시 넣을 수 있는 변수보다 불변 값을 우선시한다는 점이 조금 낯설 수 있어요. 그런데 불변 데이터는 함수형 프로그래밍의 아주 중요한 요소예요. 여러 스레드가 함께 도는 환경에서는 여러 스레드가 동시에 바꿀 수 있는 공유 변수를 관리하기 힘들어요. 또 가변 변수는 다른 함수에 넘겨졌을 때 그 값이 바뀔 수도 있는지 알기 어려울 때가 있어요.

순수 함수형 언어에는 아예 변수가 없고, 함수는 수학의 함수처럼 엄격하게 동작해요. 절차적 언어에서 변수에 값을 다시 할당해 값을 바꿀 때, 함수형 언어에서는 입력이 되는 불변 값, 불변 함수, 그리고 다른 불변 값이 결과로 나오는 구조예요. 이런 수학적인 엄격함 덕분에 프로그램의 동작을 더 꼼꼼하게 추론할 수 있어요. 그리고 이렇게 더 빡빡한 추론이 가능해야 컴파일러가 코드를 더 엄격하게 검사하고 더 효과적으로 최적화할 수 있어요. 개발자 입장에서도 올바른 코드를 이해하고 작성하기가 더 쉬워지죠. 그래서 함수형 코드가 일반적인 절차적 코드보다 디버깅하기 쉬운 경우가 많아요.

F#은 순수 함수형 언어는 아니지만 함수형 프로그래밍을 충분히 지원해요. 불변 값을 쓰는 건 좋은 습관이에요. 그렇게 해야 함수형 프로그래밍의 중요한 장점을 코드에 그대로 살릴 수 있거든요.

가변 변수 (Mutable Variables)

값을 바꿀 수 있는 변수를 만들고 싶다면 mutable 키워드를 쓰면 돼요. F#의 가변 변수는 보통 범위를 제한해서 쓰는 게 좋아요. 타입의 필드처럼 쓰거나 지역 값으로 쓸 때죠. 범위가 좁은 가변 변수는 제어하기 쉬울 뿐 아니라 잘못된 방식으로 수정될 가능성도 낮아요.

가변 변수에도 값을 정의할 때와 똑같이 let 키워드로 초기값을 줄 수 있어요. 차이는 그다음에 <- 연산자로 새 값을 다시 넣을 수 있다는 점이에요. 예시를 볼게요.

let mutable x = 1
x <- x + 1

추가로, mutable로 표시된 값이 클로저에 포착되면 자동으로 'a ref로 승격될 수 있어요. 여기에는 seq 빌더처럼 클로저를 만드는 형태도 포함돼요. 이런 일이 일어날 때 알림을 받고 싶다면 프로젝트 파일이나 컴파일러 호출 시점에 경고 3180을 켜면 돼요.

더 알아보기

  • Functions — 함수 값 바인딩과 함수 값의 타입을 더 자세히 다뤄요.
  • Literals — 리터럴의 종류와 각각이 정하는 타입을 설명해요.
  • Compiler Options--warnon 등 컴파일러 옵션과 경고 제어를 살펴볼 수 있어요.