Sum Type (서로소 유니온 타입) 그리고 패턴매칭

Tei·2020년 10월 26일
3
post-thumbnail

1. AND 타입과 OR 타입

일반적으로 우리가 사용하는 타입은 and 로 결합되는 타입입니다.

그 예시를 들자면 아래과 같습니다.

class Person {
  string name
  int age
}

즉 Person 이라는 타입은 name 과(and) age 로 이루어진 타입이라는 것이죠.

이런 타입 방법은 보편적으로 사용되지만, 만약 Alien 이라는 새로운 타입이 들어온다고 생각해 봅시다.

그리고 Alien 끼리는 서로 이름이 아닌 alienNo 라는 숫자로 부른다고 생각해봅시다.

class Alien{
  int alienNo 
  int age
}

그리고 PersonAlien 은 동등한 지위를 가지고 살아가고 있다고 가정해봅시다.

그리고 채용 시즌이 다가와 PersonAlien 은 자소서를 쓰기 시작했습니다.

class Resume{
  지원자
  경력
  특이사항
}

여기서 한가지 문제가 발생합니다. Resume 의 지원자 에는 Alien 도 들어갈 수 있어야하고 Person도 들어갈 수 있어야합니다.

여기서 생각할 수 있는 전통적인 해결책은 상속이 있습니다.

PersonAlien 의 공통된 부모 속성을 정의하고, 그 부모속성을 지원자 속성으로 사용하는 것입니다.

그럼 유기체라는 공통 부모를 설정해보죠

class Organism{
  int age
}

좋습니다. 이제 PersonAlien 도 자식 타입으로 설정할 수 있겠네요.

그런데 인공지능이 발달해서 이제 로봇들도 취업을 하는 시기가 왔습니다. 로봇들도 자소서를 쓰기 시작했습니다.

하지만 로봇은 나이도, 이름도 존재하지 않고 제조사와 일련번호로 구분이 된다고 생각해봅시다.

설계에 엄청난 문제가 생겼습니다. Resume class 에 지원자 타입은 Organism 이지만, 로봇은 Organism 이 아니기 때문입니다.

OR 타입

여기서 나올 수 있는 해법은 OR 타입(UNION 타입)입니다.

만약에 Resume 타입을 이렇게 생각하면 어떨까요?

class Resume{
  지원자 tpye: Person OR Alien OR Robot
  경력
  특이사항
}
  • 지원자는 Person 또는 Alien 또는 Robot 이다

이처럼 OR type 을 통한 접근은 문제를 쉽게 만들어줄 때가 있습니다.

2. 서로소 유니온 타입(disjoint union type)

서로소 유니온 타입은, 겹치지 않는 타입으로 이루어진 유니온 타입을 의미합니다.

가장 간단한 예시는 Boolean type 이 있습니다.

Boolean 은 True 이라면 절대 False 일 수 없고, False 라면 절대 True 일 수 없습니다.

서로소 유니온 타입과 같은 말은 Tagged union sum type 등이 있습니다.

서로소 유니온 타입이 유용한 상황은, 어떤 상태가 서로 겹치지 않는 상태 중 하나 일때 입니다.

  • ajax 요청은 실패면서 성공일 수 없습니다.
  • 결제 수단은 카드이면서 현금일 수 없습니다, (카드와 현금을 혼합한 복합결제는 복합결제 타입니다)

3.패턴매칭

함수형 언어에서는 이를 이용한 패턴매칭이라는 활용법이 있습니다(스칼라,Rust등 )

match status { 
  200 => do(OK), 
  404 => do(PageNotFound), 
  403 => do(Frobidden), 
  _ => notmatchedError, 
}

<패턴매칭의 예시>

자바스크립트에서는 언어적으로 지원하지 않지만, 제안 단계로 올라와있습니다 (https://github.com/tc39/proposal-pattern-matching)

if 문을 식으로 변경한것이 3항 연산자라면,

패턴매칭은 switch문을 식으로 변경한것이라 할 수 있습니다.

가령 네트워크 요청에서, status 상태에 따라 서로 다른 처리를 해줘야 할 경우, 이는 서로소유니온 타입이라고 할 수 있습니다.
(200 이면서 404인 상태는 존재하지 않기때문)

그렇기때문에 위와 같이 패턴매칭을 통해 상태에 따라 처리를 해줄 수 있습니다.

패턴매칭을 사용하면 선언적으로 문제를 해결할 수 있습니다.

const { matches } = require('z')

const fibo = (i) => {
  return matches(i)(
    (x = 0) => 0,
    (x = 1) => 1,
    (x = Number) => fibo(i - 1) + fibo(i - 2)
  );
};

console.log(fibo(10)); //55

n 번째 피보나치수를 구하는 식을 if문 하나 없이 구현할 수 있습니다. 이처럼 문제를 배타적인 상태로 정의한 후, 함수 내부에서 명령형을 제거하고 선언형으로 문제를 해결하는 방법입니다.

패턴매칭을 사용하면, 원하는 데이터 구조를 정하고, 그 안에서 특정한 값을 추출해 특정한 함수로 넘겨줄 수 있습니다.

해당 글의 초반부에서처럼, 객체지향은 이러한 문제를 상속과 다형성으로 해결합니다. 반면 함수형 패러다임은 이를 함수 수준에서 해결합니다.

FE 에서의 패턴매칭의 활용

React 에서도 fetch 상태에 따라 다른 view 를 그리는데 활용할 수 있습니다.

<Fetch url={API_URL}>{
    props => case (props) {
    when {loading} -> <Loading /> 
    when {error} -> <Error error={error} /> 
    when {data} -> <Page data={data} /> 
  } 
 }
</Fetch>

위 예시는 아직 제안 단계이기때문에 바로 사용하긴 어렵습니다.

그래서 자바스크립트에서 패턴 매칭을 사용할 수 있는 Daggy 라는 라이브러리가 있습니다.(https://github.com/fantasyland/daggy)

Daggy 의 사용법을 간단히 설명하면 아래와 같습니다

const Item = tagged('Item', ['title'])
const List = taggedSum('List',{
  Initial:[],
  Success:[Item],
  Failure:[]
});

tagged 함수와 taggedSum 함수를 사용하여 타입을 정의합니다.

이제 각각의 타입에 대해 패턴매칭할 함수 객체를 만들어줍니다.

const cataObject = {
  Initial:()=> console.log("empty"),
  Success:(e)=> console.log(e),
  Failure:()=> console.log("ERROR~")
}

cata 라는 함수를 통해 페턴매칭을 실행할 수 있습니다.

let list = List.Initial;
list.cata(cataObject)
// empty 를 출력

list = List.Failure
list.cata(cataObject)
//ERROR 를 출력
	
list = List.Success([{title:1},{title:2},{title:3}])
list.cata(cataObject)
//0: {title: 1}
//1: {title: 2}
//2: {title: 3}
// 를 출력

즉 list 에 어떤 타입을 넣어주냐에 따라서, 분기처리 없이 원하는 결과를 얻어낼 수 있습니다.

위에서 말했던 리액트 view 를 그리는 예제를 daggy 로 구현해본다면

fetch("something~")
.then(res=>{
	setData(List.Success(res));
})

<Container>
{
    List.cata({
        Initial:()=> <Init/>,
        Success:(data)=> <Page data={data} />,
        Error:()=> <Error error={error}/>,
        Loading:()=> <Loading /> 
    })
  } 
}
</Container>

이런 형식으로 구현되겠습니다.

만일 if 문으로 구현했다면

if (Initial) {
   return ...
}

if(Loading){
  return ...
}

if (Error) {
  return ...
}

과 같은 형식으로 구현되었을겁니다.

결론

SUM Type 그리고 패턴매칭에 대해 알아보았습니다.

그리고 자바스크립트에서 SUM Type 을 어떻게 사용할 수 있는지, 관련 라이브러리를 사용하여 알아보았습니다.

사실 TypeScript 에서는 서로소 유니온타입까진 아니어도, 유니온 타입을 일상적으로 사용하기때문에 신선한 내용이 아닐 수도 있겠습니다. 그래도 서로소 유니온 타입에 대해 이해할 수 있는 유익한 글이 되었길 바라겠습니다.

참고문서 & 읽어보면 좋을 글

profile
Being a service developer

1개의 댓글

comment-user-thumbnail
2023년 2월 13일

오랜만에 글 다시 봤는데, 정말 글을 잘 쓰신 것 같아요 👍

답글 달기