이 글은 위키북스 하스켈의 글을 읽고 정리한 것이다.
타입 클래스 Alternative
는 Control.Applicative
모듈에 아래와 같이 정의되어 있다.
class Applicative f => Alternative f where
empty :: f a
(<|>) :: f a -> f a -> f a
함수 <|>
는 영어로 or 라고 발음한다.
타입 Maybe
의 Alternative
인스턴스는 아래와 같이 구현되어 있다.
instance Alternative Maybe where
empty = Nothing
Nothing <|> x = x
x <|> _ = x
그런데 <|>
의 기능을 보면 Maybe
모노이드 중 하나인 First
와 기능이 같아 보인다.
instance Semigroup (First a) where
First Nothing <> b = b
a <> _ = a
리스트 타입의 인스턴스는 아래와 같다.
instance Alternative [] where
empty = []
(<|>) = (++)
함수 <|>
는 주로 파싱에서 사용한다고 한다. 예를 들어 아래와 같은 함수 digit
가 있다고 하자.
digit :: Int -> String -> Maybe Int
digit _ [] = Nothing
digit i (c:_)
| i > 9 || i < 0 = Nothing
| otherwise = if [c] == show i
then Just i
else Nothing
함수 digit
는 첫번째 인자로 넣은 숫자 i
가 두번째 인자로 넣은 문자열의 첫번째 글자와 같은지 확인한다.
ghci> digit 1 "123"
Just 1
ghci> digit 1 "234"
Nothing
이제 digit
와 <|>
를 이용하면 동시에 두가지 조건을 파싱할 수 있다!
binChar :: String -> Maybe Int
binChar s = digit 0 s <|> digit 1 s
이때 파싱 조건을 만족하는 선택지를 아래 두가지 중에서 고를 수가 있다.
0
으로 시작하는 문자열1
로 시작하는 문자열
This usage pattern can be described in terms of choice.
타입 클래스 MonadPlus
정의는 아래와 같다.
class Monad m => MonadPlus m where
mzero :: m a
mplus :: m a -> m a -> m a
타입 제약을 제외하면 MonadPlus
의 내용이 Alternative
와 다를 게 없어 보인다.
항등원이나 더하기 연산이 있다는 점에서 여기서 다룬 두 타입 클래스는 Monoid
와 연관이 있어 보인다.
class Monoid m where
mempty :: m
mappend :: m -> m -> m
instance Monoid [a] where
mempty = []
mappend = (++)
다른 점이 있다면 모노이드는 뭔가의 wrapper일 필요는 없다.