Kỹ thuật truy tìm ràng buộc


322

Đây là kịch bản: Tôi đã viết một số mã có chữ ký loại và GHC phàn nàn không thể suy ra x ~ y cho một số xy. Bạn thường có thể ném GHC một xương và chỉ cần thêm sự đồng hình vào các ràng buộc chức năng, nhưng đây là một ý tưởng tồi vì nhiều lý do:

  1. Nó không nhấn mạnh việc hiểu mã.
  2. Bạn có thể kết thúc với 5 ràng buộc trong đó một ràng buộc đã được xác định (ví dụ: nếu 5 bị ràng buộc bởi một ràng buộc cụ thể hơn)
  3. Bạn có thể kết thúc với các ràng buộc không có thật nếu bạn đã làm sai hoặc nếu GHC không có ích

Tôi mới dành vài giờ để chiến đấu với trường hợp 3. Tôi đang chơi syntactic-2.0và tôi đang cố gắng xác định phiên bản độc lập với tên miền share, tương tự như phiên bản được xác định trong NanoFeldspar.hs.

Tôi đã có điều này:

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

và GHC could not deduce (Internal a) ~ (Internal b), đó chắc chắn không phải là điều tôi sẽ làm. Vì vậy, hoặc tôi đã viết một số mã mà tôi không có ý định (yêu cầu ràng buộc) hoặc GHC muốn ràng buộc đó do một số ràng buộc khác mà tôi đã viết.

Hóa ra tôi cần thêm (Syntactic a, Syntactic b, Syntactic (a->b))vào danh sách ràng buộc, không ai trong số đó ngụ ý (Internal a) ~ (Internal b). Về cơ bản, tôi vấp phải những ràng buộc chính xác; Tôi vẫn không có một cách có hệ thống để tìm thấy chúng.

Câu hỏi của tôi là:

  1. Tại sao GHC đề xuất hạn chế đó? Không ở đâu trong cú pháp là có một ràng buộc Internal a ~ Internal b, vậy GHC đã lấy nó từ đâu?
  2. Nói chung, những kỹ thuật nào có thể được sử dụng để truy tìm nguồn gốc của một ràng buộc mà GHC tin rằng nó cần? Ngay cả đối với các ràng buộc mà tôi có thể tự khám phá, cách tiếp cận của tôi về cơ bản là vũ phu buộc con đường vi phạm bằng cách viết ra các ràng buộc đệ quy. Cách tiếp cận này về cơ bản là đi xuống một lỗ thỏ vô hạn của các ràng buộc và là về phương pháp kém hiệu quả nhất mà tôi có thể tưởng tượng.

21
Đã có một số cuộc thảo luận về một debugger mức loại, nhưng sự đồng thuận chung dường như được hiển thị logic nội bộ của typechecker sẽ không giúp đỡ: / Tính đến ngay bây giờ hạn chế Haskell của giải là một ngôn ngữ logic mờ đục crappy :)
Daniel Gratzer

12
@jozefg Bạn có liên kết cho cuộc thảo luận đó không?
crockeea

36
Thông thường nó sẽ giúp loại bỏ hoàn toàn chữ ký loại và để ghci cho bạn biết chữ ký đó phải là gì.
Tobias Brandt

12
Bằng cách nào đó abbị ràng buộc - nhìn vào chữ ký loại bên ngoài bối cảnh của bạn - a -> (a -> b) -> a, không phải a -> (a -> b) -> b. Có lẽ đó là nó? Với các bộ giải ràng buộc, chúng có thể ảnh hưởng đến đẳng thức bắc cầu ở bất cứ đâu , nhưng các lỗi thường hiển thị vị trí "gần" với vị trí của ràng buộc được tạo ra. Điều đó sẽ rất tuyệt mặc dù @jozefg - có thể chú thích các ràng buộc với các thẻ hoặc một cái gì đó, để cho biết chúng đến từ đâu? : s
Athan Clark

Câu trả lời:


6

Trước hết, chức năng của bạn có loại sai; Tôi khá chắc chắn rằng nó nên được (không có bối cảnh) a -> (a -> b) -> b. GHC 7.10 có phần hữu ích hơn trong việc chỉ ra điều đó, bởi vì với mã gốc của bạn, nó phàn nàn về một ràng buộc bị thiếu Internal (a -> b) ~ (Internal a -> Internal a). Sau khi sửa shareloại, GHC 7.10 vẫn hữu ích trong việc hướng dẫn chúng tôi:

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

  2. Sau khi thêm ở trên, chúng tôi nhận được Could not deduce (sup ~ Domain (a -> b))

  3. Sau khi thêm nó, chúng tôi nhận được Could not deduce (Syntactic a), Could not deduce (Syntactic b)Could not deduce (Syntactic (a -> b))

  4. Sau khi thêm ba, cuối cùng nó đánh máy; vì vậy chúng tôi kết thúc với

    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
    

Vì vậy, tôi muốn nói rằng GHC đã không vô dụng trong việc dẫn dắt chúng tôi.

Đối với câu hỏi của bạn về truy tìm nơi GHC được yêu cầu hạn chế của nó từ, bạn có thể thử cờ gỡ lỗi GHC của , đặc biệt -ddump-tc-trace, và sau đó đọc qua các bản ghi kết quả để xem nơi Internal (a -> b) ~ t(Internal a -> Internal a) ~ tđược bổ sung vào Wantedbộ, nhưng điều đó sẽ được khá đọc dài .


0

Bạn đã thử điều này trong GHC 8.8+ chưa?

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

Điều quan trọng là sử dụng loại lỗ trong số các ràng buộc: _ => your difficult type

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.