컴파일러 프라그마

컴파일러 프라그마 (Compiler Pragmas)

컴파일러 프라그마(pragma)는 컴파일러에게 추가적인 지시나 힌트를 주기 위해 쓰는 장치예요. 이 장은 Haskell 언어 그 자체에는 포함되지 않지만 실제로 널리 쓰이는 관행을 정리해 둔 내용이에요.

출처: Haskell 2010 언어 리포트

본문

일부 컴파일러 구현들은 컴파일러 프라그마(pragmas) 를 지원해요. 프라그마는 컴파일러에게 추가적인 지시나 힌트를 주기 위해 쓰이지만, Haskell 언어 그 자체의 일부는 아니며 프로그램의 의미(semantics)를 바꾸지 않아요. 이 장은 이런 기존 관행을 요약해요. 구현이 모든 프라그마를 반드시 지켜야 하는 건 아니지만, 구현이 인식하지 못하는 프라그마는 무시되어야 해요. 실제로 많은 언어 확장이 사용되고 있으므로, 구현체들은 아래에서 설명하는 LANGUAGE 프라그마를 지원하는 것이 강력히 권장돼요.

어휘적으로 프라그마는 주석(comment)처럼 나타나지만, 감싸는 문법이 {-# #-}라는 점이 달라요.

12.1 인라인 (Inlining)

decl → {-# INLINE qvars #-}
decl → {-# NOINLINE qvars #-}

INLINE 프라그마는 컴파일러에게 지정된 변수들을 사용되는 지점(use site)에서 인라인하라고 지시해요. 컴파일러는 흔히 단순한 식을 자동으로 인라인하기도 해요. NOINLINE 프라그마로 이를 막을 수 있어요.

12.2 특수화 (Specialization)

decl → {-# SPECIALIZE spec1 , … , speck #-}   (k ≥ 1)
spec → vars :: type

특수화는 오버로드된 함수를 디스패치할 때 생기는 비효율을 피하기 위해 사용돼요. 예를 들어,

factorial :: Num a => a -> a
factorial 0 = 0
factorial n = n * factorial (n-1)

{-# SPECIALIZE factorial :: Int -> Int,
                factorial :: Integer -> Integer #-}

컴파일러가 인자가 Int 또는 Integer임을 알아챌 수 있는 factorial 호출은, 오버로드된 수치 연산을 수반하지 않는 특수화된 버전의 factorial을 사용하게 돼요.

12.3 언어 확장 (Language extensions)

LANGUAGE 프라그마는 파일 헤더 프라그마(file-header pragma)예요. 파일 헤더 프라그마는 소스 파일에서 module 키워드보다 반드시 앞에 와야 해요. 파일 헤더 프라그마는 원하는 만큼 많이 쓸 수 있고, 그 앞뒤에 주석이 올 수도 있어요. 개별 언어 프라그마는 LANGUAGE 키워드로 시작하고, 그 뒤에 쉼표로 구분된 명명된 언어 기능 목록이 따라와요.

예를 들어, scoped type variables와 CPP 전처리를 활성화하려면(구현이 이 확장들을 지원한다면):

{-# LANGUAGE ScopedTypeVariables, CPP #-}

만약 Haskell 구현이 소스 파일이 요청한 언어 기능을 인식하지 못하거나 지원하지 않는다면(또는 요청된 언어 기능의 조합을 지원할 수 없다면), 그 파일을 해당 구현으로 컴파일하거나 사용하려는 모든 시도는 오류와 함께 실패해야 해요. 이식성(portability)을 위해, 동일하고 지원되는 언어 기능을 여러 번 활성화하려는 시도(예: 커맨드 라인 인자, 구현별 기능 의존성, 비표준 프라그마를 통한 경우)는 특별히 허용돼요.

LANGUAGE 프라그마를 지원하는 Haskell 2010 구현은 {-# LANGUAGE Haskell2010 #-}를 지원해야 해요. 그런 구현들은 다음의 명명된 언어 기능들도 지원할 것을 권장받아요:

PatternGuards, NoNPlusKPatterns, RelaxedPolyRec, EmptyDataDecls, ForeignFunctionInterface

이것들은 이 리포트에 통합된 일부 pre-Haskell 2010 구현들이 지원하던 명명된 언어 확장들이에요.

더 알아보기 (Learn more)

  • 프라그마는 프로그램 의미를 바꾸지 않는 컴파일러 지시라는 점에서, INLINE·NOINLINE에 대한 더 자세한 논의는 GHC 등의 구현 매뉴얼을 참고해요.
  • 언어 확장(LANGUAGE 프라그마)의 전체 목록과 적용 방식은 각 구현체 문서에서 확인할 수 있어요.