에서 워드 프로세서 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, 대답은 아니오입니다. 대부분 그렇습니다. 그러나 다른 방법이 있습니다.
코드 인라인 및 유형 응용 프로그램 전문화는 속도 (실행 시간)와 코드 크기 간의 균형을 유지합니다. 기본 수준은 코드를 부 풀리지 않고 속도를 높입니다. 더 철저한 수준을 선택하는 것은 SPECIALISE
pragma 를 통한 프로그래머의 재량에 달려 있습니다.
설명:
옵티마이 저는 또한 가져온 각 INLINABLE 오버로드 된 함수를 고려하여 M에서 호출되는 다양한 유형에 특화합니다.
f
타입 a
이 타입 클래스에 의해 구속 된 타입 변수를 포함하는 함수를 가정 해 보자 C a
. GHC는 기본적으로 (a) 동일한 모듈의 모든 함수 또는 (b) 가 표시된 경우 다른 응용 프로그램 을 가져 오는 다른 모듈 의 소스 코드에서 해당 유형 응용 프로그램으로 호출되는 경우 f
유형 응용 프로그램 (에 a
대한 대체 t
) 과 관련하여 전문화 됩니다. 에서 . 따라서, 자동 전문화가 전이되지 않습니다, 그것은 단지 접촉 수입 및 호출되는 함수 소스 코드 의를 .f
f
INLINABLE
f
B
INLINABLE
A
귀하의 예에서 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 t
Main