Skip to content

Instantly share code, notes, and snippets.

@nattybear
Last active February 12, 2023 17:47
Show Gist options
  • Save nattybear/73125b643e8c3360bdb034ed45fa9b42 to your computer and use it in GitHub Desktop.
Save nattybear/73125b643e8c3360bdb034ed45fa9b42 to your computer and use it in GitHub Desktop.
하스켈 Ordering 모노이드

이 글은 Learn You a Haskell for Great Good 중 일부를 정리한 것이다.

Ordering 모노이드

타입 Ordering은 뭔가 비교한 결과를 표현할 때 쓴다. Ordering에는 값이 세 개 있다.

data Ordering =
    LT
  | EQ
  | GT
  • LT : Less Than
  • EQ : Equal
  • GT : Greater Than

아래와 같이 함수 compare로 두 수를 비교하면 결과로 타입 Ordering의 값 중 하나가 나온다.

ghci> 1 `compare` 2
LT
ghci> 2 `compare` 2
EQ
ghci> 3 `compare` 2
GT

세미그룹과 모노이드 인스턴스는 아래와 같다.

instance Semigroup Ordering where
  LT <> _ = LT
  EQ <> y = y
  GT <> _ = GT

instance Monoid Ordering where
  mempty  = EQ
  mappend = (<>)
  • 항등원은 EQ이다.
  • <>에 먼저 들어온 것이 EQ일 경우 나중에 들어온 것이 결과가 된다.
  • 그렇지 않을 때는 그냥 먼저 들어온 것이 결과가 된다.

두 문자열의 길이를 비교해서 결과로 타입 Ordering이 나오는 함수를 만들어 보자. 그런데 만약 길이가 같으면 알파벳 순으로 크기를 결정한다.

lengthCompare :: String -> String -> Ordering
lengthCompare x y =
  let a = length x `compare` length y
      b = x `compare` y
  in if a == EQ then b else a
  • a는 길이를 비교한 결과
  • b는 알파벳순으로 비교한 결과
  • 길이가 같으면 b가 결과가 되고 그렇지 않으면 a가 결과가 된다.

Ordering도 모노이드라는 점을 이용하면 아래와 같이 더 쉽게 할 수 있다.

lengthCompare x y =
     (length x `compare` length y)
  <> (x `compare` y)
ghci> lengthCompare "zen" "ants"
LT
ghci> lengthCompare "zen" "ant"
GT

Ordering 모노이드는 먼저 오는 것이 EQ가 아니라면 먼저 온 것이 결과가 된다. 따라서 위와 같이 여러 조건을 우선 순위에 따라 비교하고 싶을 때 더 중요하다고 생각하는 조건을 맨 앞에 두면 된다.

위 예제에서 검사 조건을 하나 더 추가해보자. 이번에는 문자열 중 모음의 개수를 두 번째 조건으로 추가한다.

lengthCompare x y =
     (length x `compare` length y)
  <> (vowels x `compare` vowels y)
  <> (x `compare` y)
  where vowels = length . filter (`elem` "aeiou")

함수 vowels는 문자열을 입력하면

  • 문자열에서 "aeiou"에 속하는 글자만 filter로 골라내고
  • 그 길이가 결과로 나온다.
ghci> lengthComapre "zen" "anna"
LT
ghci> lengthComapre "zen" "ana"
LT
ghci> lengthCompare "zen" "ann"
GT

대문 링크

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment