F# 파라미터 배열(Params Array)

F# 파라미터 배열(Params Array)

어떤 함수는 인자의 개수를 미리 정할 수 없을 때가 있어요. 그럴 때 하나의 시그니처로 몇 개든 인자를 받아낼 방법이 있다면 편하겠죠. F#은 이런 상황에서 .NET파라미터 배열(parameter array) 기능을 사용합니다. 배열 요소 타입이 받을 수 있는 인자의 타입을 결정하고, ParamArray 특성이 키 역할을 해요.

출처: Microsoft Learn — Parameter arrays (F#)

본문

가끔은 서로 다른 타입의 인자를 개수 제한 없이 받아야 하는 함수를 정의해야 할 때가 있어요. 받아둘 수 있는 모든 타입에 대해 오버로드된 메서드를 일일이 만드는 건 현실적이지 않죠. .NET 구현은 이런 메서드를 파라미터 배열(parameter array) 기능으로 지원합니다. 시그니처에 파라미터 배열을 가진 메서드에는 원하는 만큼 많은 인자를 넘길 수 있고, 넘겨진 인자들은 배열로 모여요. 실제로 어떤 타입의 인자를 전달할 수 있는지는 배열 요소의 타입이 결정합니다. 만약 요소 타입을 System.Object로 정의하면, 클라이언트 코드는 어떤 타입의 값이든 넘길 수 있어요.

여기서 한 가지 제약이 있어요. F#에서 파라미터 배열은 메서드에서만 정의할 수 있고, 독립 함수나 모듈에 정의된 함수에서는 쓸 수 없어요.

다만 printfn 같은 함수는 파라미터 배열 없이도 비슷한 동작을 내요. 형식 지정자(format specifier)와 타입 추론을 이용해 여러 인자를 동적으로 처리하는 방식이에요. 즉 printfn은 파라미터 배열에 기대지 않고, F#의 타입 안전한 서식 메커니즘을 사용해 다양한 개수의 인자를 처리하면서 컴파일 시점의 타입 검사까지 보장하는 거죠.

파라미터 배열을 만들려면 ParamArray 특성을 사용합니다. 이 ParamArray 특성은 마지막 파라미터에만 적용할 수 있어요.

아래 코드는 파라미터 배열을 받는 .NET 메서드를 호출하는 모습과, F#으로 파라미터 배열을 받는 메서드를 가진 타입을 정의하는 모습을 함께 보여줍니다.

open System

type X() =
    member this.F([<ParamArray>] args: Object[]) =
        for arg in args do
            printfn "%A" arg

[<EntryPoint>]
let main _ =
    // call a .NET method that takes a parameter array, passing values of various types
    Console.WriteLine("a {0} {1} {2} {3} {4}", 1, 10.0, "Hello world", 1u, true)

    let xobj = new X()
    // call an F# method that takes a parameter array, passing values of various types
    xobj.F("a", 1, 10.0, "Hello world", 1u, true)
    0

프로젝트에서 실행하면 앞선 코드의 출력은 다음과 같아요.

a 1 10 Hello world 1 True
"a"
1
10.0
"Hello world"
1u
true

더 알아보기