2016-09-07 2 views
22

는 다음과 같은 컴파일 :`DeriveAnyClass`와 빈 인스턴스의 차이점은 무엇입니까? <a href="http://hackage.haskell.org/package/cassava">cassava</a> 패키지를 사용

{-# LANGUAGE DeriveGeneriC#-} 

import Data.Csv 
import GHC.Generics 

data Foo = Foo { foo :: Int } deriving (Generic) 
instance ToNamedRecord Foo 

을하지만, 다음은하지 않습니다

{-# LANGUAGE DeriveGeneriC#-} 
{-# LANGUAGE DeriveAnyClass #-} 

import Data.Csv 
import GHC.Generics 

data Foo = Foo { foo :: Int } deriving (Generic, ToNamedRecord) 

컴파일러 보고서 :

test.hs:7:50: 
    No instance for (ToNamedRecord Int) 
     arising from the first field of ‘Foo’ (type ‘Int’) 
    Possible fix: 
     use a standalone 'deriving instance' declaration, 
     so you can specify the instance context yourself 
    When deriving the instance for (ToNamedRecord Foo) 

이 두 가지 질문으로 나를 잎 : 두 번째 버전이 첫 번째 버전과 다른 이유는 무엇입니까? 그리고 컴파일러가 ToNamedRecord Int에 대한 인스턴스를 찾고자하는 이유는 무엇입니까?

+1

아직 'DeriveAnyClass'는 유용하지 않은 것을 보지 못했습니다. 그러나 나는 컴파일 타임 크래시를 생성하는 것을 보았다. Methinks 'tis 버기. – dfeuer

답변

15

The GHC docs 말 :

인스턴스 컨텍스트가 생성 될 Eq를 도출 할 때 사용 된 동일한 규칙 상기 (유형의 종류 * 경우) 또는 은 Functor위한 규칙 (종류하다면 유형은 (* -> *)입니다. 예를

instance C a => C (a,b) where ... 

data T a b = MkT a (a,b) deriving(C) 

에 대한 deriving 절은

instance C a => C (T a b) where {} 

제약을 생성합니다 C aC (a,b)는 데이터 생성자 인자에서 발생하지만, C a에 후자의 단순화된다.

는 그래서, Eq 규칙에 따라, 귀하의 deriving 절은 ... 동일하지 않습니다

instance ToNamedRecord Int => ToNamedRecord Foo where 

...

instance ToNamedRecord Foo where 

를 생성 ... 이전 버전은 범위에 instance ToNamedRecord Int이있는 경우에만 유효합니다 (이는 귀하의 경우에는 없음).

그러나 사양이 다소 모호하다는 것을 알게되었습니다. 예제가 실제로 해당 코드를 생성해야합니까? 아니면 instance (C a, C (a, b)) => instance C (T a b)을 생성하고 해석자가 두 번째 제약 조건을 해제해야합니까? 귀하의 예에서는 완전히 구체적인 유형이있는 필드에 대해서도 이러한 제약 조건을 생성합니다. 이 DeriveAnyClass이가 빨리 인스턴스를가 직관적 보인다 쓸 수 있도록하기위한 것입니다 것을 Eq 작품이 있지만, 주어진 방법이기 때문에

나는 버그이 전화를 주저.

+4

감사합니다. 이제는 해결중인 문제 ("인스턴스에 어떤 문맥을 부여해야합니까?")을 강조 했으므로 GHC 사람들이 왜 그런 결정을 내렸는 지 알 수 있습니다. 그럼에도 불구하고이 문제를 잘못된 것으로 간주하기 시작했습니다. . "일하는"조건은 엄청나게 구체적이며 그 조건에서 저축하는 일은 참으로 아주 작게 보입니다. –

+3

동의합니다. 대부분 (모두?)가 유용한 클래스의 'Generic' 또는'Data'와 같은 최상위 수퍼 클래스에 의존하게됩니다.이 클래스는 유형의 구조에 기반한 재귀 컨텍스트가 아닙니다. 생성 된 코드 자체가 구조적으로 반복적이기 때문에 규칙은'Eq'에 대해 이해가됩니다. –