[haskell] GHC에서 자동 전문화의 전이성

에서 워드 프로세서 GHC 7.6에 대한 :

[Y] 당신은 종종 처음에는 SPECIALIZE pragma가 필요하지 않습니다. 모듈 M을 컴파일 할 때 GHC의 옵티 마이저 (-O 포함)는 M에 선언 된 각각의 최상위 오버로드 된 함수를 자동으로 고려하여 M에서 호출되는 다양한 유형에 특화합니다. 옵티마이 저는 가져온 각 INLINABLE 오버로드 된 함수, M에서 호출되는 다양한 유형에 특화되어 있습니다.

또한 함수 f에 대한 SPECIALIZE pragma가 주어지면 GHC는 f에 의해 호출되는 모든 type-class-loaded 함수에 대해 SPECIALIZE pragma와 동일한 모듈에 있거나 INLINABLE 인 경우 자동으로 전문화를 작성합니다. 전 이적으로.

따라서 GHC는 pragma 없이 표시된 일부 / most / all (?) 함수를 자동으로 특수화해야 하며 명시 적 pragma를 사용하면 전문화가 전이됩니다. 내 질문은 : 자동 전문화 전이인가?INLINABLE

구체적으로, 다음은 작은 예입니다.

Main.hs :

import Data.Vector.Unboxed as U
import Foo

main =
    let y = Bar $ Qux $ U.replicate 11221184 0 :: Foo (Qux Int)
        (Bar (Qux ans)) = iterate (plus y) y !! 100
    in putStr $ show $ foldl1' (*) ans

Foo.hs :

module Foo (Qux(..), Foo(..), plus) where

import Data.Vector.Unboxed as U

newtype Qux r = Qux (Vector r)
-- GHC inlines `plus` if I remove the bangs or the Baz constructor
data Foo t = Bar !t
           | Baz !t

instance (Num r, Unbox r) => Num (Qux r) where
    {-# INLINABLE (+) #-}
    (Qux x) + (Qux y) = Qux $ U.zipWith (+) x y

{-# INLINABLE plus #-}
plus :: (Num t) => (Foo t) -> (Foo t) -> (Foo t)
plus (Bar v1) (Bar v2) = Bar $ v1 + v2

GHC는 호출을 전문화 plus하지만 성능을 저하 시키는 인스턴스 는 전문화 하지 않습니다 .(+)Qux Num

그러나 명시 적 pragma

{-# SPECIALIZE plus :: Foo (Qux Int) -> Foo (Qux Int) -> Foo (Qux Int) #-}

결과 전이 워드 프로세서는 표시로 전문화, 그래서 (+)전문 및 코드는 빠른 (모두 컴파일 30 배이다 -O2). 이것이 예상되는 동작입니까? (+)명시 적 pragma를 전 이적으로 전문화 해야합니까 ?


최신 정보

7.8.2에 대한 문서는 변경되지 않았으며 동작은 동일하므로이 질문은 여전히 ​​관련이 있습니다.



답변

짧은 답변 :

내가 이해 한 바와 같이 질문의 요점은 다음과 같습니다.

  • “자동화는 전이 적인가?”
  • (+)가 명시 적 pragma로 전 이적으로 전문화되기를 기대해야합니까?
  • (명백히 의도 된 것) 이것은 GHC의 버그입니까? 설명서와 일치하지 않습니까?

AFAIK, 대답은 아니오입니다. 대부분 그렇습니다. 그러나 다른 방법이 있습니다.

코드 인라인 및 유형 응용 프로그램 전문화는 속도 (실행 시간)와 코드 크기 간의 균형을 유지합니다. 기본 수준은 코드를 부 풀리지 않고 속도를 높입니다. 더 철저한 수준을 선택하는 것은 SPECIALISEpragma 를 통한 프로그래머의 재량에 달려 있습니다.

설명:

옵티마이 저는 또한 가져온 각 INLINABLE 오버로드 된 함수를 고려하여 M에서 호출되는 다양한 유형에 특화합니다.

f타입 a이 타입 클래스에 의해 구속 된 타입 변수를 포함하는 함수를 가정 해 보자 C a. GHC는 기본적으로 (a) 동일한 모듈의 모든 함수 또는 (b) 가 표시된 경우 다른 응용 프로그램 을 가져 오는 다른 모듈 의 소스 코드에서 해당 유형 응용 프로그램으로 호출되는 경우 f유형 응용 프로그램 (에 a대한 대체 t) 과 관련하여 전문화 됩니다. 에서 . 따라서, 자동 전문화가 전이되지 않습니다, 그것은 단지 접촉 수입 및 호출되는 함수 소스 코드 의를 .ffINLINABLE fBINLINABLEA

귀하의 예에서 Num다음과 같이 인스턴스를 재 작성하는 경우 :

instance (Num r, Unbox r) => Num (Qux r) where
    (+) = quxAdd

quxAdd (Qux x) (Qux y) = Qux $ U.zipWith (+) x y
  • quxAdd에서 특별히 가져 오지 않았습니다 Main. Main의 인스턴스 사전을 가져오고이 Num (Qux Int)사전 quxAdd에 대한 레코드에 포함 됩니다 (+). 그러나 사전을 가져 오지만 사전에 사용 된 내용은 가져 오지 않습니다.
  • plus호출하지 않으면 의 인스턴스 사전에 레코드에 quxAdd저장된 함수를 사용합니다 . 이 사전은 호출 사이트 (에서 )에서 컴파일러에 의해 설정됩니다 .(+)Num tMain

답변