Skip to content

Instantly share code, notes, and snippets.

@nattybear
Last active January 3, 2021 08:56
Show Gist options
  • Save nattybear/86eb28e25f82affc58f5b8a2f02c6742 to your computer and use it in GitHub Desktop.
Save nattybear/86eb28e25f82affc58f5b8a2f02c6742 to your computer and use it in GitHub Desktop.
하스켈 달러 표시

우선 순위

하스켈 함수도 우선 순위가 있다.

예를 들어 함수 *+ 보다 우선 순위가 높다.

GHCi> 1 + 2 * 3
7

그래서 1 + 2를 먼저 계산하지 않고 우선 순위가 더 높은 2 * 3을 먼저 계산한다.

물론 괄호를 이용하면 우선 순위를 높게 만들 수 있다.

GHCi> (1 + 2) * 3
9

우선 순위는 함수를 정의할 때 정할 수 있는데 Hoogle에서 소스 코드를 직접 보거나 아래처럼 인터프리터에서 :i 명령어로 확인할 수 있다. iinfo의 약자이다. info는 information의 약ㅈ...

GHCi> :i (+)
class Num a where
  (+) :: a -> a -> a
  ...
        -- Defined in ‘GHC.Num’
infixl 6 +

infixl라는 단어 오른쪽에 적힌 숫자 6이 우선 순위를 나타낸다. 우선 순위는 숫자가 높을 수록 먼저 계산한다.

함수 *의 우선 순위는 아래와 같다.

GHCi> :i (*)
class Num a where
  ...
  (*) :: a -> a -> a
  ...
        -- Defined in ‘GHC.Num’
infixl 7 *

함수 *의 우선 순위는 7이고 +의 우선 순위는 6으로 *의 우선 순위가 더 크기 때문에 먼저 계산하는 것이다.

우선 순위 방향

우선 순위는 크기 뿐만 아니라 방향도 있다. associative

예를 들어 빼기 - 같은 연산은 왼쪽부터 먼저 한다.

GHCi> 1 - 2 - 3
-4
GHCi> 1 - (2 - 3)
2

그런데 ^ 같은 연산은 오른쪽부터 먼저 한다.

GHCi> 2 ^ 1 ^ 2
2
GHCi> (2 ^ 1) ^ 2
4

우선 순위 방향도 크기와 같은 방법으로 확인할 수 있다.

class Num a where
  ...
  (-) :: a -> a -> a
  ...
        -- Defined in ‘GHC.Num’
infixl 6 -

infixl 6에서 lleft를 의미한다. 그래서 함수 -는 왼쪽부터 먼저 계산한다.

반면에 함수 ^infixr로 오른쪽부터 계산한다.

(^) :: (Num a, Integral b) => a -> b -> a       -- Defined in ‘GHC.Real’
infixr 8 ^

함수의 우선 순위

지금까지 다룬 함수들은 모두 infix 연산자였다.

infix 함수가 아닌 함수의 우선 순위는 10으로 제일 높다. 그래서 만약 infix 연산자와 그냥 함수가 섞여 있는 경우에는 괄호가 없다면 그냥 함수를 항상 먼저 계산한다.

add :: Int -> Int -> Int
add x y = x + y
GHCi> 2 * 3 `add` 4
14
GHCi> (2 * 3) `add` 4
10

함수는 왼쪽 먼저 계산한다.

multiply :: Int -> Int -> Int
multiply x y = x * y
GHCi> 1 `add` 2 `multiply` 3
9
GHCi> 1 `add` (2 `multiply` 3)
7

달러 표시

하스켈에는 아래와 같은 함수가 있다.

($) :: (a -> b) -> a -> b
f $ x = f x
  • 첫번째 인자로 타입이 a -> b인 함수 f를 넣는다.
  • 두번째 인자로 값 x를 넣는다.
  • 함수 f에 값 x를 적용한 값을 리턴한다.

타입과 내용만 봤을 때는 그냥 f x와 뭐가 다른지 어디에 쓰는 것인지 알 수가 없다.

함수 $의 비밀은 바로 우선 순위 크기와 방향에 있다.

GHCi> :i ($)
($) ::
  forall (r :: GHC.Types.RuntimeRep) a (b :: TYPE r).
  (a -> b) -> a -> b
        -- Defined in ‘GHC.Base’
infixr 0 $
infixr 0 $
  • infix 연산자이고 우선 순위 크기가 무려 0으로 제일 낮다.
  • 오른쪽부터 계산한다.

대부분의 프로그래밍 언어에서 우선 순위를 바꾸고 싶을 때 보통 괄호를 사용한다.

GHCi> putStrLn (show (read "1" + 2))
3

그런데 위 코드처럼 괄호가 많아지면 가독성이 떨어진다. LISP는 어쩌라고

이때 함수 $를 사용하면 괄호를 쓰지 않고도 우선 순위를 바꿀 수 있다.

GHCi> putStrLn $ show $ read "1" + 2
3

그냥 print를 쓰면 되잖아

괄호는 쌍으로 적어야 하지만 $는 한 개만 적으면 되니까 글자 수도 이득이다!

대문 링크

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