Maybe 타입 알아보기

2017년 03월 31일


Maybe 타입

지금까지 다룬 배열과 객체는 자바스크립트 기본 내장 타입이었습니다.

이번 강좌에서 다룰 Maybe 타입은 자바스크립트에 기본적으로 없는 타입입니다. 때문에 직접 구현하거나 라이브러리를 사용해서 추가해야합니다.

강좌에서는 구현보단 추상에 집중할 것이기 때문에 잘 구현된 라이브러리의 타입을 사용합니다. 여기서는 Sanctuary에서 제공하는 Maybe 타입을 사용합니다. Sanctuary는 Ramda와 호환되는 타입과 유용한 함수들을 제공하는 함수형 프로그래밍 라이브러리입니다.

sanctuary 사용하기

우선 sanctuary를 프로젝트에 추가합니다. 패키지 매니저를 이용해서 간단히 설치할 수 있습니다.

yarn add sanctuary

설치가 완료됐다면 다음과 같이 임포트해서 사용합니다.

import * as S from 'sanctuary';

Maybe 살펴보기

이번 강좌에서 살펴볼 타입 Maybe는 값이 있거나 없는 경우를 표현합니다.

사용 예시로 배열에서 원소를 검색하는 상황을 들 수 있습니다. 기존의 방식으로는 검색한 결과가 배열에 포함되지 않는 경우 undefined를 반환했다면, Maybe를 사용한 방식은 항상 Maybe를 반환하는 것이 특징입니다.

좀 더 구체적으로는, 값이 있는 경우 Just를 반환하고, 없는 경우는 Nothing을 반환합니다. Just는 단순히 값을 저장하는 객체고, Nothing은 값이 없음을 표현하는 싱글턴 객체입니다.

코드로 표현하면 다음과 같습니다.

import * as R from 'ramda';
import * as S from 'sanctuary';

function find(pred, xs) {
  for (const x of xs)
    if (pred(x))
      return S.Just(x);

  return S.Nothing;
}

const xs = R.range(0, 5);
const p = R.equals(3);
const q = R.equals(42);

find(p, xs); // Just(3)
find(q, xs); // Nothing

값이 있는 경우는 S.Just를 호출해 값이 있는 Maybe를 표현하고 값이 없을때는 S.Nothing 싱글턴을 이용해서 표현합니다.

Maybe의 기본적인 기능

Maybe는 값이 있을수도, 없을수도 있는 경우를 표현하는데 특화된 타입입니다. 이에 특화된 동작도 여러가지 형태로 제공되고 있습니다.

이 중 가장 먼저 소개할 것은 Just와 Nothing을 구분하는 isJust와 isNothing 속성입니다.

모든 Maybe 객체는 isJust와 isNothing 속성을 갖기 때문에 조건문으로 검사할 수 있습니다.

import * as R from 'ramda';
import * as S from 'sanctuary';

function find(pred, xs) {
  for (const x of xs)
    if (pred(x))
      return S.Just(x);

  return S.Nothing;
}

const xs = R.range(0, 5);
const result = find(R.equals(42), xs);

if (result.isNothing) 
  console.log('찾는 값이 없습니다');

다음으로 Maybe 객체에서 값을 추출하기 위한 fromMaybe 함수가 있습니다.

이 함수는 인자로 받은 Maybe가 Just인지 Nothing인지 어떠한 가정도 하지 않습니다. 때문에 Nothing인 경우에도 올바르게 동작할 수 있도록 디폴트 인자를 받습니다.

import * as S from 'sanctuary';

const a = S.Just('Merong');
const b = S.Nothing;

S.fromMaybe('Bikini', a); // 'Merong'
S.fromMaybe('Bikini', b); // 'Bikini'

마지막으로 비어있는 값을 Nothing으로, 다른 값은 Just로 만드는 toMaybe 함수가 있습니다.

이 함수는 기존의 undefined를 반환하는 함수를 Maybe를 반환하도록 바꿀 때 유용합니다.

import * as R from 'ramda';
import * as S from 'sanctuary';

S.toMaybe(null); // Nothing
S.toMaybe(42);   // Just(42)

const find = (pred, xs) => S.toMaybe(xs.find(pred));
const xs = R.range(0, 5);

find(R.equals(42), xs); // Nothing
find((x) => x > 3, xs); // Just(4)

이제 더 이상 새로 배울 기능은 없습니다. 기존에 사용했던 함수를 그대로 Maybe에 적용할 수 있습니다.