haskell - 설치 - 제약 조건을 이용한 전문화



install ghc (1)

나는 GHC가 클래스 제약으로 함수를 특수화하는 데 문제가있다. 여기에 내 문제에 대한 최소한의 예가있다 : Foo.hsMain.hs 두 파일이 컴파일되고 (GHC 7.6.2, ghc -O3 Main ) 실행됩니다.

참고 : Foo.hs 정말 아래로 제거됩니다. 제약 조건이 필요한 이유를 알고 싶다면 here 좀 더 자세한 코드를 볼 수 here . 단일 파일에 코드를 삽입하거나 다른 많은 사소한 변경을하면 GHC는 plusFastCyc 대한 호출을 간단히 설명합니다. 인라인으로 표시된 경우에도 plusFastCyc 가 GHC에서 인라인하기에는 너무 크기 때문에 실제 코드에서는 발생하지 않습니다. 요점은 plusFastCyc 대한 호출을 plusFastCyc 하고 인라인하지 않는 것입니다. plusFastCyc 는 실제 코드의 여러 위치에서 호출되기 때문에 GHC에 강제로 적용 할 수있는 경우에도 그러한 큰 함수를 복제하는 것은 바람직하지 않습니다.

관심있는 코드는 plusFastCycFoo.hs 이며 여기에서 재현됩니다.

{-# INLINEABLE plusFastCyc #-}
{-# SPECIALIZE plusFastCyc :: 
         forall m . (Factored m Int) => 
              (FastCyc (VT U.Vector m) Int) -> 
                   (FastCyc (VT U.Vector m) Int) -> 
                        (FastCyc (VT U.Vector m) Int) #-}

-- Although the next specialization makes `fcTest` fast,
-- it isn't useful to me in my real program because the phantom type M is reified
-- {-# SPECIALIZE plusFastCyc :: 
--          FastCyc (VT U.Vector M) Int -> 
--               FastCyc (VT U.Vector M) Int -> 
--                    FastCyc (VT U.Vector M) Int #-}

plusFastCyc :: (Num (t r)) => (FastCyc t r) -> (FastCyc t r) -> (FastCyc t r)
plusFastCyc (PowBasis v1) (PowBasis v2) = PowBasis $ v1 + v2

Main.hs 파일에는 ~ 3 초 내에 실행되는 fcTestforall 전문화를 사용하여 -O3으로 컴파일 될 때 ~ 83 초 내에 실행되는 fcTest 있습니다.

코어는 vtTest 테스트에서 범용 벡터 코드가 fcTest 사용되는 동안 추가 코드가 Int s 등의 Unboxed 벡터에 특수화되고 있음을 보여줍니다 . 10 번 라인에서 GHC는 167 행의 일반 버전과 비교하여 plusFastCyc 의 특수 버전을 작성하고 있음을 알 수 있습니다. 전문화 규칙은 225 행에 있습니다.이 규칙은 270 행에서 실행되어야합니다. ( main6 호출 iterate main8 y 이므로 main8main8plusFastCyc 되어야하는 곳입니다.)

필자의 목표는 vtTest 을 전문으로하여 fcTest 만큼 빠른 fcTest 를 만드는 것입니다. 이 작업을 수행하는 두 가지 방법을 찾았습니다.

  1. Explicity는 GHC.Exts 에서 inline 으로 전화합니다. GHC.ExtsfcTest .
  2. plusFastCyc 에서 Factored m Int 제약 조건을 제거합니다.

옵션 1은 만족스럽지 않습니다. 왜냐하면 실제 코드 기반 인 plusFastCyc 는 자주 사용되는 연산이고 매우 큰 함수이므로 매번 사용할 때마다 인라인되지 않아야하기 때문입니다. 오히려 GHC는 plusFastCyc 의 특수 버전을 호출해야합니다. 옵션 2는 실제 코드에서 제약 조건을 필요로하기 때문에 실제로 옵션이 아닙니다.

INLINE , INLINABLESPECIALIZE 사용하여 다양한 옵션을 시도했지만 아무 것도 작동하지 않는 것 같습니다. ( 편집 : 내 예제를 작게 만들기 위해 plusFastCyc 를 너무 많이 제거했기 때문에 INLINE 은 함수가 INLINE 될 수 있습니다. plusFastCyc 가 너무 plusFastCyc 코드는 실제 코드에서 발생하지 않습니다.)이 특정 예제에서는 match_co: needs more cases 얻지 match_co: needs more cases 하거나 RULE: LHS too complicated to desugar match_co: needs more cases 예제를 최소화하기 전에 많은 match_co 경고를 match_co 에도 불구하고 RULE: LHS too complicated to desugar match_co: needs more cases (및 here ) 경고에 RULE: LHS too complicated to desugar . 아마도 "문제"는 규칙에서 Factored m Int 제약 조건입니다. 해당 제약 조건을 변경하면 fcTestfcTest 만큼 빠르게 실행됩니다.

GHC가 좋아하지 않는 것을하고 있습니까? GHC가 plusFastCyc 전문으로하지 않는 이유는 무엇입니까? 어떻게 만들 수 있습니까?

최신 정보

문제는 GHC 7.8.2에서 지속되므로이 질문은 여전히 ​​적절합니다.


또한 GHC는 유형 클래스 인스턴스 선언을 SPECIALIZE 하는 옵션을 제공합니다. 나는 Foo.hs 의 (확장 된) 코드를 다음과 같이 Foo.hs .

instance (Num r, V.Vector v r, Factored m r) => Num (VT v m r) where 
    {-# SPECIALIZE instance ( Factored m Int => Num (VT U.Vector m Int)) #-}
    VT x + VT y = VT $ V.zipWith (+) x y

그러나 이러한 변화는 원하는 속도 향상을 달성하지 못했습니다. 이 성능 향상을 달성하기 위해 다음과 같이 VT U.Vector m Int 유형에 대한 특수 인스턴스를 동일한 함수 정의로 수동으로 추가하는 것이 었습니다.

instance (Factored m Int) => Num (VT U.Vector m Int) where 
    VT x + VT y = VT $ V.zipWith (+) x y

이 경우 LANGUAGE 에서 OverlappingInstancesFlexibleInstances 를 추가해야합니다.

흥미롭게도 예제 프로그램에서 모든 SPECIALIZEINLINABLE pragma를 제거해도 중복 인스턴스로 얻은 속도 향상은 유지됩니다.





ghc