제약이있는 전문화


156

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

참고 : Foo.hs 실제로 제거되었습니다. 제약 조건이 필요한 이유를 보려면 여기에서 더 많은 코드를 볼 수 있습니다 . 코드를 단일 파일에 넣거나 기타 여러 가지 사소한 변경을 수행하면 GHC는 단순히 호출을 인라인합니다 plusFastCyc. 실제 코드에서는 표시되지 않은 경우 plusFastCyc에도 GHC가 인라인 하기 에 너무 커서이 문제 가 발생하지 않습니다 INLINE. 요점은 인라인이 아닌에 대한 호출 을 특수화 하는 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: 파일은 두 드라이버가 vtTest, 2 ~ 3 초 실행하고 fcTest사용 -O3으로 컴파일시 ~ 83초에서 실행되는, forall'D 전문화.

핵심 쇼 에 대한 vtTest테스트, 추가 코드가 전문화되고있는 Unboxed이상 벡터 Int일반적인 벡터 코드가 사용되는 동안, 등의, fcTest. 라인 (10)에, 당신은 GHC이의 전문 버전 쓰기 않는 것을 볼 수 있습니다 plusFastCyc나는이 규칙이 라인 (270) (에 발사한다고 생각 라인 전문화에 대한 규칙은 라인 225에 167의 일반 버전에 비해 main6통화 iterate main8 y그래서 main8입니다 plusFastCyc전문화해야 할 곳 )

내 목표는 전문화 하여 fcTest최대한 빨리 만드는 것 vtTest입니다 plusFastCyc. 이 작업을 수행하는 두 가지 방법을 찾았습니다.

  1. 명시 적으로 호출 inline에서 GHC.Exts에서 fcTest.
  2. Factored m Int제약 조건을 제거하십시오 plusFastCyc.

실제 코드 기반 plusFastCyc에서 자주 사용되는 작업이고 매우 큰 기능 이기 때문에 옵션 1은 만족스럽지 않으므로 사용 시마다 인라인되지 않아야합니다. 대신 GHC는의 특수 버전을 호출해야합니다 plusFastCyc. 실제 코드에는 제약 조건이 필요하기 때문에 옵션 2는 실제로 옵션이 아닙니다.

내가 사용하는 (그리고 사용하지 않는) 다양한 옵션을 시도했습니다 INLINE, INLINABLE그리고 SPECIALIZE, 그러나 아무것도 작동하는 것 같다 없습니다. ( 편집 : plusFastCyc예제를 작게 만들기 위해 너무 많이 제거 했을 INLINE수 있으므로 함수가 인라인 될 수 있습니다.이 코드 plusFastCyc는 너무 커서 실제 코드에서는 발생하지 않습니다 .)이 특정 예제에서는 그렇지 않습니다. 어떤 점점 match_co: needs more casesRULE: LHS too complicated to desugar(그리고 여기에서 나는 많은 얻고 있었다 불구하고) 경고를 match_co예를 최소화하기 전에 경고를. 아마도 "문제"는 Factored m Int규칙 의 제약 일 것입니다. 해당 제약 조건을 변경하면 fcTest최대한 빨리 실행됩니다 vtTest.

GHC가 싫어하는 일을하고 있습니까? GHC가 왜 전문가가 아닌데 plusFastCyc어떻게 만들 수 있습니까?

최신 정보

GHC 7.8.2에서도 문제가 지속되므로이 질문은 여전히 ​​관련이 있습니다.


3
난 그냥 특정 m , 즉 전문을 시도했습니다 M. 이것으로 작업이 완료되었지만 실제 프로그램에서 특정 팬텀 유형을 구체화 할 수는 없습니다.
crockeea

또한 GHC 버그 보고서 ghc.haskell.org/trac/ghc/ticket/8668을 제출 했지만 문제는 여전히 열려 있습니다. 버그 보고서 프로세스를 통해 질문을 약간 정리하는 데 도움이되었으므로 진행 상황을 파악하는 것이 더 쉬울 것입니다.
crockeea

@monojohnny 죄송 합니다만, 신고하실 수 있습니다. 나는 GHC에게 상당히 합리적인 일을하라고 요구하고 있지만 그렇게하지 않을 것입니다. 내가 잘못하고 있는지 또는 이것이 해결 방법이있을 수있는 컴파일러와의 특유한 것인지 확실하지 않습니다. 현재 해킹에 대한 특정 라이브러리의 전문화 및 규칙에 대한 해결 방법을 보았습니다. 따라서 커뮤니티의 누군가가 나보다 더 많은 GHC 경험을 가진 사람이 전문화를 달성하는 방법을 알고 있기를 바랍니다.
crockeea

1
내 의견의 색조에 대해 사과드립니다-이 사이트에 대한 나의 가장 큰 기여는 아닙니다-귀하의 게시물에 실제로 아무런 문제가 없습니다 (내가 생각하는 성가심의 원인이라는 이해력이 부족합니다!)
monojohnny

@monojohnny 사과는 받아 들였지만, downvote가 지금 잠겨 있다는 것은 너무 나쁩니다. ;-)
crockeea

답변:


5

GHC는 SPECIALIZE형식 클래스 인스턴스 선언에 대한 옵션도 제공합니다 . 나는 (확장 된) 코드로 이것을 시도 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

OverlappingInstances그리고 FlexibleInstances에 추가가 필요합니다 LANGUAGE.

흥미롭게도 예제 프로그램에서 겹치는 인스턴스로 얻은 속도 향상은 모든 SPECIALIZEINLINABLEpragma 를 제거하더라도 유지됩니다 .


확실히 최적은 아니지만 실제로 목표를 달성하는 첫 번째 솔루션이므로 지금 당장 취할 것 같습니다 ...
crockeea
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.