2017-10-13 17 views
0

하스켈은 모두 추상에 관한 것입니다. 그러나 추상화는 모든 추상 (다형성) 데이터 (힙의 포인터)의 공통 표현으로 인해 추가 CPU 사이클과 추가 메모리 사용을 필요로합니다. 고성능 요구로 추상 코드를 더 잘 재생할 수있는 몇 가지 방법이 있습니다. 필자가 아는 한, 한 가지 방법은 전문화입니다. 기본적으로 추가 코드 생성 (수동 또는 컴파일러)이 맞습니까?하스켈 (GHC) 전문 투어 및 효율적인 유형 가족

의 모든 코드는 아래 엄격한이라고 가정하자

을 우리가 함수 sum있는 경우 (컴파일러가 더 최적화를 수행하는 데 도움이?) : 우리는 specialize를 사용하여의 특화된 버전을 생성 할 수 있습니다

sum :: (Num a) => a -> a -> a 

을 pragma :

{-#SPECIALIZE sum :: Float -> Float -> Float#-} 

이제 haskell 컴파일러가 컴파일시에 sum을 두 개의 Float에 호출한다고 결정하면, 그것의 특수한 버전을 사용할 것입니다. 힙 할당은 없습니다.

기능 완료. 클래스 인스턴스에 동일한 프라그 마를 적용 할 수 있습니다. 논리는 여기에 변하지 않습니다, 그렇죠?

하지만 데이터 유형은 어떻게됩니까? 여기에 TypeFamilies이 담당하고있는 것으로 의심됩니다.

종속 길이 인덱스 목록을 전문화 해 봅시다.

--UVec for unboxed vector 
class UVec a where 
    data Vec (n :: Nat) a :: * 

instance UVec Float where 
    data Vec n Float where 
    VNilFloat :: Vec 0 Float 
    VConsFloat :: {-#UNPACK#-}Float -> 
        Vec n Float -> 
        Vec (N :+ 1) Float 

그러나 Vec에 문제가 있습니다. UVec의 각 인스턴스가 동일한 생성자를 사용하여 Vec을 제공 할 필요가 없으므로 생성자에서 패턴 일치를 패턴화할 수 없습니다. 이렇게하면 Vec의 각 인스턴스에 대해 Vec에 각 함수를 구현해야합니다 (패턴 일치가 없으면 Vec에서 다형성이 될 수 없음을 의미 함). 그런 경우에 가장 좋은 방법은 무엇입니까?

답변

1

당신이 말한대로 UVec a에 일치 패턴을 적용 할 수 없으므로 a이 무엇인지 모릅니다. 하나의 옵션은 사용자 정의 함수로 벡터 클래스를 확장하는 다른 typeclass를 사용하는 것입니다.

class UVec a => UVecSum a where 
    sum :: UVec a -> a 

instance UVecSum Float where 
    sum = ... -- use pattern match here 

경우, 나중에, 우리는 v :: UVec Float가, 우리는 인스턴스에 정의 된 Float - 특정 코드가 호출됩니다 sum v를 사용합니다.

0

부분 답변이지만, 아마도 도움이 될 수 있습니다.

필자가 아는 한, 한 가지 방법은 전문화입니다. 기본적으로 추가 코드 생성 (수동 또는 컴파일러)이 맞습니까?

예, 이것은 C++ 템플릿의 코드 인스턴스 생성과 유사합니다.

이제 haskell 컴파일러가 컴파일 타임에 두 개의 Floats에 대해 sum을 호출 할 수 있다고 판단하면 특수 버전을 사용하게됩니다. 힙 할당은 없습니다.

예 가능하면 컴파일러에서 특수 버전을 호출합니다. 힙 할당과 관련하여 어떤 의미인지는 확실하지 않습니다.

의존형 벡터에 대해 : 보통 (Idris에서 알 수 있습니다.) 가능하면 벡터 길이가 컴파일러에 의해 제거됩니다. 더 강력한 유형 확인을위한 것입니다. 런타임시 길이 정보는 쓸데 없으며 삭제 될 수 있습니다.

+1

런타임 정보 : haskell에는 전체 종속 유형이 없습니다. Haskell은 런타임 값과 타입을 구별합니다. 따라서 Vec의 길이는 지워질 수 있습니다 (길이가 런타임 값이 아닌 유형 (또는 종류)이지만 haskell은 런타임에 유형을 보존 할 수 없기 때문에). – russoulmc