트랙
/
Elm
Elm
/
연습 문제
/
표 주세요!
표 주세요!

표 주세요!

학습 연습 문제

소개

패턴 매칭

패턴 매칭은 표현력 있는 분기 코드를 가능하게 하고, 구조 분해는 값과 변수를 우아하게 묶어줘요.

간단한 패턴 매칭

패턴 매칭은 case문을 사용해 값을 변수에 묶거나, 와일드카드 _로 값을 버릴 수 있어요.

type Entity = Alien | Stranger (Maybe String) | Friend { name: String }

hello : Entity -> String
hello entity =
    case entity of
        -- Custom type variant
        Alien -> "Hello, you are not from around here are you?"
        -- Binding to a litteral value nested in Stranger
        Stranger (Just nametag) -> "Hello, erm... " ++ nametag ++ "."
        -- Discarding Friend's data
        Friend _ -> "Hi!"
        -- All other cases
        _ -> "Hello stranger!"

구조 분해

구조 분해는 데이터에 가능한 형태가 하나뿐일 때마다 let 바인딩, 함수 인자, 그리고 물론 case 식에서 값을 묶을 수 있어요.

pairSum : ( Int, Int ) -> Int
pairSum pair =
    -- Destructuring of a pair in a 'let' binding
    let ( x, y ) = pair
    in x + y

-- Destructuring in the function argument
pairSum : ( Int, Int ) -> Int
pairSum ( x, y ) = x + y

-- Custom type containing a single variant
type Container = Box String

-- Destructuring in the function argument
unbox : Container -> String
unbox (Box str) = str

-- Destructuring combined with pattern matching
unboxMaybe : Maybe Container -> Maybe String
unboxMaybe maybeContainer =
    case maybeContainer of
        Nothing -> Nothing
        Just (Box "42") -> Just "The answer to the universe!"
        Just (Box str) -> Just str

구조 분해는 레코드에도 사용할 수 있고, as 키워드와 함께 쓸 수도 있어요.

type alias Circle =
    { radius : Float
    , center : ( Float, Float )
    }

perimeter : Circle -> Float
perimeter { radius } =
    2 * pi * radius

left : Circle -> Float
left { radius, center } =
    -- the pair center cannot be pattern matched directly in the function argument
    -- so we do it in a 'let' statement
    let ( x, _ ) = center
    in x - radius

-- using the 'as' keyword to bind both the fields and the whole record
smaller : Float -> Circle -> Circle
smaller reduction ({ radius } as circle) =
    if reduction < radius then
        { circle | radius = radius - reduction }
    else
        circle

지침

IT 헬프데스크에서 일하고 있고, 티켓 시스템을 더 효율적으로 개선해서 관리자에게 통계를 제공하고 싶어요.

티켓에는 상태(new, in progress...)와 작성자(사용자 이름과 직원 ID로 식별돼요)가 있고, IT 직원에게 할당될 수 있으며, 댓글 기록이 담겨 있어요.

지금의 티켓 시스템을 개선할 네 가지 작업이 있어요.

1. 빈 댓글 찾아내기

빈 댓글은 인터페이스를 어지럽히고 아무 정보도 주지 않으니, 이런 댓글을 걸러내고 싶어요.

사용자/댓글 쌍을 받아서 빈 댓글이면 True를 반환하는 헬퍼 함수 emptyComment를 정의해요.

함수 인자에서 바로 구조 분해를 사용해 사용자와 댓글을 추출해요. 사용자 정보는 필요 없으니 무시해요.

emptyComment ( User "Alice", "" )
-- => True

2. 작성자가 남긴 댓글 수 세기

관리자는 티켓 처리 과정에 사용자들이 얼마나 참여하는지에 대한 통계를 원해요. 관리자는 티켓 작성자가 댓글을 몇 개나 남겼는지 확인해 달라고 해요.

티켓을 받아서 티켓 작성자가 추가한 댓글 수를 반환하는 numberOfCreatorComments를 정의해요.

함수 인자에서 구조 분해를 사용해 Ticket 타입에서 레코드를 추출하면서 동시에 레코드에서 필요한 필드도 추출해요. 그다음 let 바인딩에서 createdBy를 구조 분해해서 관련 댓글을 셀 수 있게 해요. List 함수로 개수를 세고, 익명 함수의 인자에서 구조 분해를 사용해 사용자/댓글 쌍을 분리해요.

numberOfCreatorComments
numberOfCreatorComments
    (Ticket
        { status = Closed
        , createdBy = ( User "Chiaki", 1 )
        , assignedTo = Nothing
        , comments = [ ( User "Chiaki", "Never mind, fixed it." ) ]
        }
    )
-- => 1

3. Dev Team에 할당된 티켓 찾아내기

일부 티켓은 Dev Team의 Alice, Bob, Charlie에게 에스컬레이션해야 해요. 이런 티켓이 잘 진행되고 있는지 계속 지켜보는 게 중요해요.

티켓이 Dev Team 구성원 중 한 명에게 할당됐는지 확인하는 헬퍼 함수 assignedToDevTeam을 정의해요.

함수 인자에서 구조 분해를 사용해 Ticket 타입에서 레코드와 필요한 필드를 추출해요. 그다음 하나의 case 문으로 티켓이 Alice, Bob, Charlie 중 누구에게 할당됐는지 확인하는데, 재귀 패턴 매칭으로 각자의 사용자 이름을 추출하고 리터럴 패턴 매칭으로 일치시켜요.

assignedToDevTeam
    (Ticket
        { status = InProgress
        , createdBy = ( User "Bill", 2 )
        , assignedTo = Just (User "Alice")
        , comments = [ ( User "Bill", "What's an 'undefined'?" ) ]
        }
    )
-- => True

4. IT 직원에게 티켓 할당하기

때로는 여러 티켓을 다른 IT 직원에게 다시 할당해야 해요.

이 작업을 도와줄 assignTicketTo 함수를 정의해요. 이 함수는 티켓을 할당할 사용자와 티켓, 두 개의 인자를 받아요. 티켓의 상태가 New라면 새 사용자에게 할당하고 상태를 InProgress로 바꿔요. 다른 상태라면 티켓을 새 사용자에게 그냥 다시 할당해요. 단, 상태가 Archived인 티켓은 전혀 수정하면 안 돼요.

함수 인자에서 구조 분해를 사용해 Ticket 타입에서 레코드와 필요한 필드를 추출하고, as 키워드로 레코드 전체를 그대로 잡아 둬요. 하나의 case 문으로 상태를 패턴 매칭하고, as 키워드로 잡아 둔 원본 레코드를 수정해 알맞은 티켓을 반환해요.

assignTicketTo (User "Danny")
    (Ticket
        { status = New
        , createdBy = ( User "Jesse", 3 )
        , assignedTo = Just (User "Alice")
        , comments = [ ( User "Jesse", "I've been waiting for 6 months!!" ) ]
        }
    )
-- => Ticket
--        { status = InProgress
--        , createdBy = ( User "Jesse", 3 )
--        , assignedTo = Just (User "Danny")
--        , comments = [ ( User "Jesse", "I've been waiting for 6 months!!" ) ]
--        }
GitHub에서 편집 링크가 새 창이나 탭에서 열려요
Elm Exercism

표 주세요! 문제를 시작해 볼 준비가 됐나요?

Exercism에 가입하고 Elm 트랙을 개념 28개연습 문제 110개, 그리고 실제 사람의 멘토링과 함께 배우고 익혀 보세요. 모두 무료예요.