시나리오는 다음과 같습니다. 유형 서명으로 일부 코드를 작성했으며 GHC는 일부 x
및에 대해 x ~ y를 추론 할 수 없다고 불평 y
합니다. 일반적으로 GHC에 뼈를 던지고 단순히 함수 제약 조건에 동형을 추가 할 수는 있지만 몇 가지 이유로 나쁜 생각입니다.
- 코드 이해를 강조하지 않습니다.
- 하나가 충분할 경우 5 개의 제약 조건으로 끝날 수 있습니다 (예 : 5가 하나 이상의 특정 제약 조건에 의해 암시되는 경우)
- 뭔가 잘못했거나 GHC가 도움이되지 않으면 가짜 제약 조건이 생길 수 있습니다
방금 사례 3과 싸우는 데 몇 시간을 보냈습니다.에 대해 놀고 있으며 syntactic-2.0
에 정의 된 버전과 share
유사한 도메인 독립적 버전을 정의하려고 했습니다 NanoFeldspar.hs
.
나는 이것을 가지고 있었다 :
{-# LANGUAGE GADTs, FlexibleContexts, TypeOperators #-}
import Data.Syntactic
-- Based on NanoFeldspar.hs
data Let a where
Let :: Let (a :-> (a -> b) :-> Full b)
share :: (Let :<: sup,
Domain a ~ sup,
Domain b ~ sup,
SyntacticN (a -> (a -> b) -> b) fi)
=> a -> (a -> b) -> a
share = sugarSym Let
그리고 GHC could not deduce (Internal a) ~ (Internal b)
, 확실히 내가 가고있는 것이 아닙니다. 그래서 내가 의도하지 않은 코드를 작성했거나 (제약이 필요함) GHC는 내가 작성한 다른 제약으로 인해 그 제약을 원했습니다.
(Syntactic a, Syntactic b, Syntactic (a->b))
제약 목록 에 추가해야한다는 것이 밝혀졌습니다 (Internal a) ~ (Internal b)
. 나는 기본적으로 올바른 제약 조건을 우연히 발견했습니다. 나는 여전히 체계적인 방법으로 찾을 수 없습니다.
내 질문은 :
- GHC가 그 제약을 제안한 이유는 무엇입니까? 구문상의 어느 것도 제약
Internal a ~ Internal b
이 없으므로 GHC는 어디서 그것을 끌어 냈습니까? - 일반적으로 GHC가 필요하다고 생각하는 제약의 기원을 추적하기 위해 어떤 기술을 사용할 수 있습니까? 내가 발견 할 수있는 제약 조건조차도 내 접근 방식은 본질적으로 재귀 제약 조건을 실제로 작성하여 문제의 경로를 강요하는 것입니다. 이 접근법은 기본적으로 무한한 토끼 구멍을 뚫고 나가는 가장 효율적인 방법에 관한 것입니다.
답변
우선, 함수의 유형이 잘못되었습니다. 나는 그것이 (컨텍스트없이) 있어야한다고 확신합니다 a -> (a -> b) -> b
. GHC 7.10은 원래 코드를 사용하면 제약 조건 누락에 대해 불평하기 때문에 그 점을 지적하는 데 다소 도움이됩니다
Internal (a -> b) ~ (Internal a -> Internal a)
. share
의 유형을 수정 한 후 GHC 7.10은 다음과 같이 안내합니다.
-
Could not deduce (Internal (a -> b) ~ (Internal a -> Internal b))
-
위의 내용을 추가하면
Could not deduce (sup ~ Domain (a -> b))
-
그를 추가 한 후, 우리는 수
Could not deduce (Syntactic a)
,Could not deduce (Syntactic b)
과Could not deduce (Syntactic (a -> b))
-
이 세 가지를 추가 한 후에는 마지막으로 형식 검사를 수행합니다. 그래서 우리는 결국
share :: (Let :<: sup, Domain a ~ sup, Domain b ~ sup, Domain (a -> b) ~ sup, Internal (a -> b) ~ (Internal a -> Internal b), Syntactic a, Syntactic b, Syntactic (a -> b), SyntacticN (a -> (a -> b) -> b) fi) => a -> (a -> b) -> b share = sugarSym Let
그래서 저는 GHC가 우리를 이끄는 데 쓸모가 없다고 말하고 싶습니다.
GHC로부터의 제약 조건을 가져 추적에 대한 질문에 관해서는, 당신은 시도 할 수 GHC의 디버깅 플래그를 특히, -ddump-tc-trace
다음 위치를 확인하기 위해 결과 로그를 읽어 Internal (a -> b) ~ t
와 (Internal a -> Internal a) ~ t
받는 추가 Wanted
세트,하지만 꽤 오랜 읽을 수 있습니다 .
답변
GHC 8.8 이상에서 시도 했습니까?
share :: (Let :<: sup,
Domain a ~ sup,
Domain b ~ sup,
SyntacticN (a -> (a -> b) -> b) fi,
_)
=> a -> (a -> b) -> a
share = sugarSym Let
핵심은 제약 조건 중 유형 구멍을 사용하는 것입니다. _ => your difficult type