본문 바로가기

23년 1학기 학교공부/프로그래밍언어개론

[OCaml] Pattern matching

목차

    728x90
    반응형
    SMALL

    📁 match-with expression

    값의 형태에 따라 다른 행동을 수행하도록 하는 expression이다.

    해당 표현은 expression이므로 값으로 도출된다.

     

    기본형은 다음과 같다.

    match [expression] with

    | [pattern1] -> [expression1]

    | [pattern2] -> [expression2]

    ...

    | [patternN] -> [expressionN]

    위의 pattern들은 상수(constant) 혹은 변수(variable)로 구성되어 있다.

    만약 [pattern1]부터 Wildcard라면, 그 밑으로는 무시된다. 

    expression1, ... N 들의 타입이 같아야한다.

     

    match with 구문을 실행하는 과정은 다음과 같다.

    1. expression을 계산한다.
    2. 위의 계산 결과를 pattern1과 매칭한다.
    3. 매칭되는 경우 expression1을 계산하고, 그 결과가 전체 match-with expression의 결과가 된다.
    4. 매칭을 실패하는 경우 pattern2와 매칭한다.
    5. ...

     

    처리하지 않은 형태가 있을 경우 warning이 발생한다. 예를 들면 다음과 같은 경우가 있다.

    [1; 2; 3]
    | [] -> ~~
    | [h] -> ~~
    | [h1; h2] -> ~~

    위 코드에서 원소 3개짜리를 처리하지 않았기 때문에 warning이 발생한다.

     

    📝 Example1

    📌 패턴은 상수인지 변수인지에 따라 다르게 동작한다.

     

     

    패턴이 상수인 경우, [expression] 값이 패턴과 일치하는지를 매칭한다.

    일치할 경우 매칭에 성공하고, 불일치할 경우 매칭에 실패한다.

     

    패턴이 변수인 경우, [expression] 값을 변수에 바인딩한다.

    이 경우에는 항상 매칭에 성공한다.

     

    예시는 다음과 같다.

    module F = Format
    module Fib = struct
    	let rec fib i =
        	match i with
            | 0 -> 0 (* when i is 0 *)
            | 1 -> 1 (* when i is 1 *)
            | n -> fib (n-2) + fib (n-1) (* otherwise *)
    end
    
    let _ =
    	let _ = F.printf "Res: %d\n" (Fib.fib 0) in 
    	let _ = F.printf "Res: %d\n" (Fib.fib 1) in 
    	let _ = F.printf "Res: %d\n" (Fib.fib 2) in
        	F.printf "Res: %d\n" (Fib.fib 3)

     

    위 fib 재귀함수는 음수가 오면 무한반복한다. 이를 커버하기 위해 아래와 같은 방법을 이용한다.

    match i with
    | 0 -> 0
    | n when n > 0 -> ~~
    | n -> ~~

     

    이때 음수를 커버하겠다는 목적으로  when n < 0 구문을 마지막 패턴의 n 뒤에 쓰게 되면 오류가 발생한다.

    pattern에 when 구문이 존재하면 컴파일러는 무조건 '부분적 커버'라고 생각하기 때문에, 마지막 변수에는 when절이 존재하면 안된다.

     

    📌 [patternN]에 있는 변수는 무조건 [expressionN]에서 사용되어야 한다.

    쓰지 않으면 오류가 난다. 왱?

     

    🔎 Caution1 : variables in patterns

    패턴내의 변수는 값과 바인딩되므로 항상 매칭에 성공한다.때문에 변수가 앞 패턴에 등장하는 경우, 이후의 패턴은 매칭될 기회를 잃는다.

    위 예시에서 pattern의 변수 x, y는 binding occurrence이며, 이는 바인딩 발생이라는 뜻이다.

    위에서 x = 0, y = 1이라과 정의하였어도 패턴 내에 들어오면 x, y를 0과 1로 치환하여 생각하는게 아니라, 무조건 i를 x, y에 바인딩한다는 뜻이다.

     

    이때 패턴 내의 x, y 변수는 바깥의 x, y를 shadowing하며, 이름만 같을 뿐 서로 다른 변수이다.

     

     

    📝 Example 2

    📌 [expression]에 임의의 expression을 사용할 수 있다.

    📌 [patternN]에 Wildcard를 사용할 수 있다.

    [patternN]에 Wildcard를 사용하게 되면 변수와 같이 항상 매칭에 성공하지만, 매칭된 [expression] 결과값을 [expressionN]에서 사용하지 않겠다는 의미이다.

     

    예시는 다음과 같다.

    let _ =
        let even_or_odd i =
            match i mod 2 with
            | 0 -> F.printf "Even\n"
            | 1 -> F.printf "Odd\n"
            | _ -> (* Is this pattern required? *) F.printf "Unknwon\n"
        in
        let _ = even_or_odd 0 in (* Even *)
        let _ = even_or_odd 1 in (* Odd *)
        let _ = even_or_odd 2 in (* Even *)
        even_or_odd 3 (* Odd *)

    위 예시에서 [expression]에 i mod 2라는 임의의 expression을 사용하였다.

     

    🔎 Caution2 : exhaustive matching

    위 예시에서 Wildcard 패턴을 제외하면 컴파일 warning이 발생한다.i mod 2 결과는 무조건 0 혹은 1이라고 생각해서 wildcard를 제거하면 안된다.

     

    컴파일러는 expression의 결과값이 아니라 타입을 기반으로 패턴매칭을 검사하기 때문에,위와 같이 결과값이 int인 경우 모든 int에 대해 커버해야한다.

     

     

    📝 Example3

     

     

     

     

    📁 패턴 매칭 사용 시 주의사항

    Caution1 : variables in patterns

     

    Caution2 : exhaustive matching

     

    Caution3 : type of pattern matching expression

     

     

     

     

    728x90
    반응형
    LIST