Loops

Loops (반복문)

F#에서는 반복을 위해 세 가지 루프 표현식을 쓸 수 있어요. 리스트·시퀀스·배열 같은 열거 가능한 컬렉션을 훑을 땐 for...in, 정수 구간을 하나씩 세어가며 반복할 땐 for...to, 조건이 참인 동안 계속 반복할 땐 while...do를 사용합니다. 이 세 가지를 차례로 살펴볼게요.

출처

본문

for...in Expression

for...in열거 가능한 컬렉션(구간 표현식, 시퀀스, 리스트, 배열, 그리고 열거를 지원하는 다른 어떤 구성)에서 패턴과 매치되는 요소들을 하나씩 반복할 때 쓰는 루프 구조예요.

구문

for pattern in enumerable-expression do
    body-expression

알아두기

for...in은 열거 가능한 컬렉션의 값들을 순회하기 때문에, 다른 .NET 언어의 for each 문과 비교할 수 있어요. 다만 for...in은 컬렉션 전체를 그냥 순회하는 것에 더해 컬렉션에 대해 패턴 매칭까지 지원한다는 점이 달라요.

열거 가능한 표현식은 열거 가능한 컬렉션으로 지정하거나, .. 연산자를 써서 구간으로 지정할 수 있어요. 열거 가능한 컬렉션에는 리스트, 시퀀스, 배열, 집합(set), 맵(map) 등이 있고, System.Collections.IEnumerable을 구현하는 어떤 타입이든 사용할 수 있어요.

.. 연산자로 구간을 표현할 때는 다음 구문을 써요.

start .. finish

증분값(이를 skip 이라고 해요)을 포함한 버전도 쓸 수 있어요.

start .. skip .. finish

skip 값을 지정하지 않으면 컬렉션에서 다음으로 생성되는 값이 1씩 증가해요. skip을 지정하면 그 값만큼 증가하지요.

패턴에서 매치된 값은 본문 표현식 안에서 그대로 사용할 수 있어요.

이어지는 코드 예시들이 for...in의 다양한 쓰임을 보여줄게요.

// Looping over a list.
let list1 = [ 1; 5; 100; 450; 788 ]
for i in list1 do
   printfn "%d" i

출력은 다음과 같아요.

1
5
100
450
788

다음 예시는 시퀀스를 순회하면서, 단순 변수 대신 튜플 패턴을 쓰는 모습을 보여줘요. 이 시퀀스 표현식의 -> 연산자는 시퀀스 표현식과 다른 계산 표현식에서 do yield의 줄임말이에요. -> 연산자 덕분에 그 값이 시퀀스의 일부가 되는 표현식을 지정할 수 있죠. 자세한 내용은 SequencesComputation Expressions를 참고해요.

let seq1 = seq { for i in 1 .. 10 -> (i, i*i) }
for (a, asqr) in seq1 do
  printfn "%d squared is %d" a asqr

출력은 다음과 같아요.

1 squared is 1
2 squared is 4
3 squared is 9
4 squared is 16
5 squared is 25
6 squared is 36
7 squared is 49
8 squared is 64
9 squared is 81
10 squared is 100

다음 예시는 간단한 정수 구간을 순회하는 방법이에요.

let function1() =
  for i in 1 .. 10 do
    printf "%d " i
  printfn ""
function1()

function1의 출력은 다음과 같아요.

1 2 3 4 5 6 7 8 9 10

이번에는 skip이 2인 구간을 순회해요. 구간의 하나 걸러 요소만 포함되지요.

let function2() =
  for i in 1 .. 2 .. 10 do
     printf "%d " i
  printfn ""
function2()

function2의 출력은 다음과 같아요.

1 3 5 7 9

문자 구간도 사용할 수 있어요.

let function3() =
  for c in 'a' .. 'z' do
    printf "%c " c
  printfn ""
function3()

function3의 출력은 다음과 같아요.

a b c d e f g h i j k l m n o p q r s t u v w x y z

음수 skip 값을 써서 역순으로 반복할 수도 있어요.

let function4() =
    for i in 10 .. -1 .. 1 do
        printf "%d " i
    printfn " ... Lift off!"
function4()

function4의 출력은 다음과 같아요.

10 9 8 7 6 5 4 3 2 1 ... Lift off!

구간의 시작과 끝도 표현식(예를 들어 함수)이 될 수 있어요. 아래 코드에서 확인해 볼게요.

let beginning x y = x - 2*y
let ending x y = x + 2*y

let function5 x y =
  for i in (beginning x y) .. (ending x y) do
     printf "%d " i
  printfn ""

function5 10 4

이 입력값으로 function5를 실행한 출력은 다음과 같아요.

2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

다음 예시는 루프에서 요소가 필요하지 않을 때 와일드카드 문자(_)를 쓰는 모습을 보여줘요.

let mutable count = 0
for _ in list1 do
   count <- count + 1
printfn "Number of elements in list1: %d" count

출력은 다음과 같아요.

Number of elements in list1: 5

참고로, for...in은 시퀀스 표현식이나 다른 계산 표현식 안에서도 쓸 수 있는데, 그 경우 for...in맞춤형 버전이 사용돼요. 자세한 내용은 Sequences, Async expressions, Task expressions, Computation Expressions를 참고해요.

for...to Expression

for...to 표현식은 루프 변수의 값 범위를 순회하며 반복할 때 쓰는 루프 구조예요.

구문

for identifier = start [ to | downto ] finish do
    body-expression

알아두기

identifier의 타입은 startfinish 표현식의 타입으로부터 추론돼요. 이 두 표현식의 타입은 32비트 정수여야 해요.

엄밀히는 표현식이지만, for...to는 명령형 프로그래밍 언어의 전통적인 문장에 가까워요. body-expression의 반환 타입은 반드시 unit이어야 해요. 다음 예시들이 for...to의 다양한 쓰임을 보여줄게요.

// A simple for...to loop.
let function1() =
  for i = 1 to 10 do
    printf "%d " i
  printfn ""

// A for...to loop that counts in reverse.
let function2() =
  for i = 10 downto 1 do
    printf "%d " i
  printfn ""

function1()
function2()

// A for...to loop that uses functions as the start and finish expressions.
let beginning x y = x - 2*y
let ending x y = x + 2*y

let function3 x y =
  for i = (beginning x y) to (ending x y) do
     printf "%d " i
  printfn ""

function3 10 4

앞선 코드의 출력은 다음과 같아요.

1 2 3 4 5 6 7 8 9 10
10 9 8 7 6 5 4 3 2 1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

while...do Expression

while...do 표현식은 지정한 테스트 조건이 참인 동안 반복 실행(루핑)을 수행할 때 쓰는 루프 구조예요.

구문

while test-expression do
    body-expression

알아두기

test-expression을 평가해서 참이면 body-expression을 실행하고, 다시 테스트 표현식을 평가해요. body-expression의 타입은 반드시 unit이어야 해요. 테스트 표현식이 거짓이 되면 반복이 끝나요.

다음 예시가 while...do의 쓰임을 보여줄게요.

open System

let lookForValue value maxValue =
  let mutable continueLooping = true
  let randomNumberGenerator = new Random()
  while continueLooping do
    // Generate a random number between 1 and maxValue.
    let rand = randomNumberGenerator.Next(maxValue)
    printf "%d " rand
    if rand = value then
       printfn "\nFound a %d!" value
       continueLooping <- false

lookForValue 10 20

앞선 코드의 출력은 1과 20 사이의 무작위 숫자들의 흐름이며, 마지막 숫자는 10이에요.

13 19 8 18 16 2 10
Found a 10!

참고로, while...do도 시퀀스 표현식이나 다른 계산 표현식 안에서 쓸 수 있으며, 그 경우 while...do맞춤형 버전이 사용돼요. 자세한 내용은 Sequences, Async expressions, Task expressions, Computation Expressions를 참고해요.

더 알아보기