2017-10-05 18 views
12

Tôi đã hiển thị một đồng nghiệp Free khi tôi gặp phải hành vi GHC tò mò mà tôi thực sự không hiểu. Đây là một đơn giản, chương trình giả tạo rằng typechecks:Tại sao tôi gặp lỗi loại trong chương trình này khi tôi thêm định nghĩa không liên quan?

import Prelude hiding (readFile, writeFile) 
import Control.Monad.Free 
import Data.Functor.Sum 

data FileSystemF a 
    = ReadFile FilePath (String -> a) 
    | WriteFile FilePath String a 
    deriving (Functor) 

data ConsoleF a 
    = WriteLine String a 
    deriving (Functor) 

data CloudF a 
    = GetStackInfo String (String -> a) 
    deriving (Functor) 

type App = Free (Sum FileSystemF (Sum ConsoleF CloudF)) 

readFile :: FilePath -> App String 
readFile path = liftF (InL (ReadFile path id)) 

writeFile :: FilePath -> String -> App() 
writeFile path contents = liftF (InL (WriteFile path contents())) 

Tôi đã thử thêm định nghĩa khác, nhưng nó không hoàn toàn đúng:

writeLine :: String -> App() 
writeLine line = liftF (InR (WriteLine line())) 

Vấn đề ở đây là tôi đã mất tích InL khác. Định nghĩa chính xác phải là:

writeLine :: String -> App() 
writeLine line = liftF (InR (InL (WriteLine line()))) 

Tuy nhiên, đó không phải là vấn đề. Điều kỳ lạ đối với tôi là lỗi kiểu mà GHC tạo ra khi tôi thêm định nghĩa đầu tiên, không chính xác của tôi là writeLine. Cụ thể, nó được sản xuất hai lỗi loại:

/private/tmp/free-sandbox/src/FreeSandbox.hs:26:27: error: 
    • Couldn't match type ‘ConsoleF’ with ‘Sum ConsoleF CloudF’ 
     arising from a functional dependency between constraints: 
      ‘MonadFree 
      (Sum FileSystemF (Sum ConsoleF CloudF)) 
      (Free (Sum FileSystemF (Sum ConsoleF CloudF)))’ 
      arising from a use of ‘liftF’ at src/FreeSandbox.hs:26:27-66 
      ‘MonadFree 
      (Sum FileSystemF ConsoleF) 
      (Free (Sum FileSystemF (Sum ConsoleF CloudF)))’ 
      arising from a use of ‘liftF’ at src/FreeSandbox.hs:29:18-48 
    • In the expression: liftF (InL (WriteFile path contents())) 
     In an equation for ‘writeFile’: 
      writeFile path contents = liftF (InL (WriteFile path contents())) 
    | 
26 | writeFile path contents = liftF (InL (WriteFile path contents())) 
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 

/private/tmp/free-sandbox/src/FreeSandbox.hs:29:18: error: 
    • Couldn't match type ‘Sum ConsoleF CloudF’ with ‘ConsoleF’ 
     arising from a functional dependency between: 
      constraint ‘MonadFree 
         (Sum FileSystemF ConsoleF) 
         (Free (Sum FileSystemF (Sum ConsoleF CloudF)))’ 
      arising from a use of ‘liftF’ 
      instance ‘MonadFree f (Free f)’ at <no location info> 
    • In the expression: liftF (InR (WriteLine line())) 
     In an equation for ‘writeLine’: 
      writeLine line = liftF (InR (WriteLine line())) 
    | 
29 | writeLine line = liftF (InR (WriteLine line())) 
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 

Thứ hai của hai lỗi (phần trên dòng 29) có ý nghĩa. Đó là lỗi tôi mong đợi. Nhưng lỗi trên dòng 26 hoàn toàn cản trở tôi. Định nghĩa của writeFile là chính xác! Việc thêm định nghĩa không chính xác của tôi là writeLine sẽ không có bất kỳ ảnh hưởng nào trên writeFile, phải không? Chuyện gì vậy?

Tôi đã có thể tái tạo điều này trên GHC 8.0.2 và GHC 8.2.1. Tôi muốn biết đây có phải là lỗi trong GHC hay không (vì vậy tôi có thể báo cáo lỗi này) hoặc nếu đó là vấn đề với mã của tôi mà tôi không hiểu.

+6

Ồ, đây là một điều tuyệt vời. Lưu ý rằng nếu bạn đặt định nghĩa 'writeLine' không chính xác _before_ các định nghĩa khác thì lỗi đáng ngờ sẽ biến mất. :) – Alec

+4

Tôi đã mở [GHC TraC# 14327] (https://ghc.haskell.org/trac/ghc/ticket/14327) để theo dõi vấn đề này. –

+0

Vấn đề dường như có liên quan đến FD, vì chuyên 'liftF ':: Functor f => f a -> Tự do f a' được loại bỏ lỗi bổ sung. Có lẽ tôi đang thiếu một cái gì đó. – Alec

Trả lời

Các vấn đề liên quan