Kısıtlamaları İzleme Teknikleri


322

Bir tür imzası ile bazı kodlar yazdım ve GHC bazıları için x ~ y anlamak olamazdı yakınır: İşte senaryo xve y. Genellikle GHC'ye bir kemik atabilir ve fonksiyon kısıtlamalarına izomorfizmi ekleyebilirsiniz, ancak bu birkaç nedenden dolayı kötü bir fikirdir:

  1. Kodun anlaşılmasını vurgulamaz.
  2. Birinin yeterli olacağı 5 kısıtlama ile karşılaşabilirsiniz (örneğin, 5'in bir başka kısıtlamayla ima edilmesi halinde)
  3. Yanlış bir şey yaptıysanız veya GHC yardımcı olmuyorsa sahte kısıtlamalarla karşılaşabilirsiniz.

Vaka 3 ile mücadele etmek için sadece birkaç saat geçirdim syntactic-2.0ve ile tanımlanan versiyona sharebenzer şekilde, alandan bağımsız bir versiyon tanımlamaya çalışıyordum NanoFeldspar.hs.

Bu vardı:

{-# 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

ve GHC could not deduce (Internal a) ~ (Internal b), ki bu kesinlikle benim istediğim şey değildi. Yani ya ben (bu kısıtlama gerekli) niyetinde değildi bazı kod yazmıştı, ya da GHC ben yazmıştı diğer bazı kısıtlamalar nedeniyle bu kısıtlama istedi.

(Syntactic a, Syntactic b, Syntactic (a->b))Kısıtlama listesine eklemem gerektiği ortaya çıktı , hiçbiri ima etmedi (Internal a) ~ (Internal b). Temel olarak doğru kısıtlamalarla karşılaştım; Onları bulmak için hala sistematik bir yolum yok.

Sorularım:

  1. GHC bu kısıtlamayı neden önerdi? Sözdizimsel olarak hiçbir yerde bir kısıtlama yoktur Internal a ~ Internal b, öyleyse GHC bunu nereden çekti?
  2. Genel olarak, GHC'nin ihtiyaç duyduğuna inandığı bir kısıtlamanın kökenini izlemek için hangi teknikler kullanılabilir? Hatta kısıtlamaları için bunu yapabilirsiniz kendimi keşfetmek, yaklaşımım esasen fiziksel olarak özyinelemeli kısıtlamaları yazarak kusurlu yolunu zorlayarak kaba edilir. Bu yaklaşım temelde sınırların sonsuz bir tavşan deliğinden aşağı iniyor ve hayal edebileceğim en az verimli yöntemle ilgili.

21
Tip düzeyinde bir hata ayıklayıcı üzerinde bazı tartışmalar oldu, ancak genel fikir birliği daktilodaki iç mantığın yardımcı olmadığını gösteriyor: / Şu andan itibaren Haskell'in kısıtlayıcı çözücü berbat bir opak mantık dili :)
Daniel Gratzer

12
@jozefg Bu tartışma için bir bağlantınız var mı?
crockeea

36
Genellikle tür imzasını tamamen kaldırmak ve ghci'nin imzanın ne olması gerektiğini düşündüğünü söylemesine yardımcı olur.
Tobias Brandt

12
Bir şekilde ave bbağlı - bağlamınızın dışındaki tür imzasına bakın - a -> (a -> b) -> adeğil a -> (a -> b) -> b. Belki de budur? Kısıt çözücülerle geçişli eşitliği her yerde etkileyebilirler , ancak hatalar genellikle kısıtlamanın indüklendiği yere "yakın" bir konum gösterir. @Jozefg olsa da bu iyi olurdu - belki de nereden geldiğini göstermek için etiketler ya da başka bir şeyle kısıtlamalar ek açıklama? : s
Athan Clark

Yanıtlar:


6

Her şeyden önce, işleviniz yanlış türde; (Bağlam olmadan) olması gerektiğinden eminim a -> (a -> b) -> b. GHC 7.10 bunu belirtmekte biraz daha yararlıdır, çünkü orijinal kodunuzla eksik bir kısıtlamadan şikayet eder Internal (a -> b) ~ (Internal a -> Internal a). shareTürü düzelttikten sonra , GHC 7.10 bize rehberlik etmede yardımcı olmaya devam ediyor:

  1. Could not deduce (Internal (a -> b) ~ (Internal a -> Internal b))

  2. Yukarıdakileri ekledikten sonra, Could not deduce (sup ~ Domain (a -> b))

  3. Bunu ekledikten sonra Could not deduce (Syntactic a),Could not deduce (Syntactic b) veCould not deduce (Syntactic (a -> b))

  4. Bu üçünü ekledikten sonra, sonunda daktilo denetler; bu yüzden sonunda

    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

Dolayısıyla GHC'nin bize liderlik etmede faydası olmadığını söyleyebilirim.

GHC'nin kısıtlama gereksinimlerini nereden aldığını izleme ile ilgili sorunuza gelince , özellikle GHC'nin hata ayıklama bayraklarını deneyebilir -ddump-tc-traceve daha sonra sete nerede Internal (a -> b) ~ tve (Internal a -> Internal a) ~ teklendiğini görmek için sonuç günlüğünü okuyabilirsiniz Wanted, ancak bu oldukça uzun bir okuma olacaktır. .


0

Bunu GHC 8.8+ sürümünde denediniz mi?

share :: (Let :<: sup,
          Domain a ~ sup,
          Domain b ~ sup,
          SyntacticN (a -> (a -> b) -> b) fi,
          _) 
      => a -> (a -> b) -> a
share = sugarSym Let

Anahtar kısıtlamalar arasında tip deliği kullanmaktır: _ => your difficult type

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.