모나드는 "함수의 결합 방식이 정의된 자료형"이라고 이해하면 사용하는 데 큰 무리가 없다. 요컨데 Monad 클래스를 구현한 자료형이다.
class Monad m where
(>>=) :: m a -> ( a --> m b) -> m b
return :: a -> m a
(>>) :: m a -> m b -> m b
fail :: String -> m a
리스트에서 값을 찾아 위치를 알려주는 함수를 만든다고 생각해보자. 만약 위치를 찾는 데 실패한다면, 다시 말해 리스트에 없는 값을 찾으려고 시도한다면 어떻게 해야할까? 여기에는 세 가지 방법이 있다. 가장 흔한 방법은 음수를 돌려주는 것이다. 리스트에서 값의 위치는 항상 양수기 때문에 실패했다는 것을 알려줄 수 있는 좋은 방법이 된다. 그러나 어느 멍청한 프로그래머가 이것을 위치로 받아들이고 리스트에 접근하려고 시도할 수 있다.
list = ['a','b','c'] p = find 'd' list list !! p -- error!!!
어느 멍청한 프로그래머가 그런 짓을 하겠느냐고 생각할지도 모르지만 실제로 많은 프로그램들이 이런 문제를 겪고 있다. 좀 더 나은 방법은 결과와 함께 성공 여부를 돌려주는 것이다. 그러나 실패했는 지 확인하지 않으면 이 방법도 무용지물이긴 마찬가지다.
Maybe 모나드를 사용하면 이런 경우를 간단하고 안전하게 다룰 수 있다. Maybe 모나드는 Just와 Nothing, 두 종류의 생성자가 있다. >>=로 결합된 함수들에서 Just로 생성된 값은 정상적으로 전달되지만 Nothing으로 생성된 값은 함수들을 건너 뛴다.
-- 예제1
do
p <- find 'b' list -- Just 2
return (list !! p)
⇒ Just 'b'
-- 예제2
do
p <- find 'd' list -- Nothing
return (list !! p)
⇒ Nothing
예제2에서 list !! p는 에러를 일으키지 않는다. 이것은 Maybe 모나드의 >>= 함수가 왼쪽에 Nothing 값이 있으면 오른쪽 함수를 실행시키지 않고 바로 Nothing 값을 돌려주도록 되어있기 때문이다. 예외(exception)와 비슷하지만 프로그래머가 일일이 잡지 않아도 안전하게 작동한다는 점이 다르다. Maybe 모나드의 구현은 아래와 같다.
instance Monad Maybe where
(Just x) >>= f = f x
Nothing >>= f = Nothing
return = Just
fail = Nothing
>>는 기본적으로 >>=를 바탕으로 구현되어 있기 때문에 특별한 경우가 아니면 직접 구현할 필요가 없다.
m >> f = m >>= \_ -> f
Haskell에서 널리 쓰이는 모나드에 대한 설명은 Jeff Newbern의 All About Monads를 참고하기 바란다.