2017-11-08 6 views
9

해결합니다.이 코드를 고려 유형의 오류

Foo.hs:16:17: 
    Could not deduce (Foo a) arising from a use of ‘bar’ 
    from the context (SomeClass a) 
     bound by the type signature for foo :: SomeClass a => a -> Int 
     at Foo.hs:15:8-32 
    Possible fix: 
     add (Foo a) to the context of 
     the inferred type of x :: Int 
     or the type signature for foo :: SomeClass a => a -> Int 
    In the expression: bar t 
    In an equation for ‘x’: x = bar t 
    In the expression: let x = bar t in x 

는이 문제를 해결하는 방법은 두 가지가 있습니다 : 대신, GHC는 그래서 Foo a => SomeClass a 예를 사용하여 수행해야합니다 가정 foo에서

  1. , bar t
  2. let x = bar t in x 변화에 라인 instance SomeClass Int을 덧붙이을 내 프로그램

여기 무슨 일이 일어나고 있습니까? 이 문제가 발생하는 이유는 무엇이며 왜 이러한 수정이 효과가 있습니까?


이 예제는 물론 실제 문제로 단순화되었습니다. 다국어 변환을위한 Cubix 프레임 워크 (arxiv.org/pdf/1707.04600)에서 작업하는 동안 발생했습니다.

내 실제 문제는 제약 조건 InjF f IdentL FunctionExpL ("f는 식별자가 함수 호출에서 함수를 나타내는 데 사용될 수있는 언어입니다")가있는 함수와 관련됩니다. 내가 (거짓) Could not deduce FunctionIdent :<: f 오류를주는, typechecker가 점유에 (overlappable) 인스턴스 (FunctionIdent :<: f) => InjF f IdentL FunctionExpL 있습니다.

특정 Foo의 범위에 InjF Foo IdentL FunctionExpL 인스턴스가있는 경우에도이 오류가 지속되므로 다른 인스턴스가 문제를 해결해야한다고 예측하는 leftaroundabout의 답변은 전체 기사가 아닙니다.

+2

'{- # OVERLAPPABLE # -}'과'{- # LANGUAGE FlexibleContexts # -} '는 아무런 영향을주지 않습니다. 컴파일을하는 또 다른 방법 :'x' :: Int'를'let' 바인딩에 추가하십시오. – Alec

+1

아마도 가장 시끄러운 것은 모듈의 all_에 인스턴스가 없을 때 typechecks ... – leftaroundabout

답변

3

그 이유는 컴파일러가 가능한 일반적으로 x을 시도한다는 것입니다 : 그것은 (SomeClass a) => Int되고 싶어 (당신은 스스로 그것을 쓴 경우 모호한 형식을 것이 통지). 이런 종류의 이상한 로컬 타입을 막는 한 가지 방법은 -XMonoLocalBinds을 활성화하는 것입니다.

이제 컴파일러는 형식 검사를 계속합니다. 이 시점에서 정확히 instance SomeClass이 하나 있는데, 즉 catch-all (Foo a) => SomeClass a이므로 모호성이 없습니다. (원칙적으로 하스켈은 인스턴스 해결에서 모호함을 완전히 금하고 있습니다; OVERLAPPABLE은 이것을 뒤집습니다. 그러나 실제로는 필요가있을 때만 동작합니다 (예 : instance SomeClass Int이있는 경우처럼). 따라서 컴파일러는 즉시 해당 인스턴스를 커밋하여 을 제거합니다. 유형 검사는 c입니다. 실제로 클래스 제약 조건을 인스턴스의 제약 조건으로 대체하려는 상황에서는이 작업이 필요합니다. 이것은 주어진 예에서 쓸모없는 것처럼 보일 수 있지만, 그 는 슈퍼 클래스로 표현할 수없는 수 있기 때문에 훨씬 더 합리적인 코드보다 형태

instance Bar a => SomeClass (Maybe a) 

...의 인스턴스를 가질 때 실제로 결정적 제약이 없으며 겹침없이 완벽하게 괜찮습니다. 컴파일러가 이러한 상황에서 Bar a으로 해결되는 제약 조건을 줄이지 않으면 실질적으로 Maybe 유형을 해결할 수 없습니다.

중재 : 중첩되는 인스턴스를 피하십시오. 가능한 경우 수퍼 클래스 선언에 의해 클래스 관계를 표현하고, 그렇지 않으면 제약 조건을 GADT로 구체화하십시오 (어색하지만 어떤 제약 조건이 사용 될지에 대한 정확한 제어권을 제공함).

+0

1) Foo a => SomeClass a)가 범위에있는 유일한 인스턴스 란 무엇입니까? 선언문의 (SomeClass a) 제약 조건은 어떻습니까? –

+0

2) 단순화하기 위해 SomeClass (Maybe a) 제약 조건을 즉시 단순화해야하는 이유는 무엇입니까? 선언 문맥을 이미 살펴본 후 그 결의안을 끝까지 연기 할 수없는 이유는 무엇입니까? –

+0

3) 이것은 내가 제공 한 단순화 된 예제를 설명하는 데 도움이되지만, 실제 예제에서는 생략합니다. 실제 사례를 제공하기 위해 내 게시물을 수정합니다. –