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.
Ồ, đâ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
Tôi đã mở [GHC TraC# 14327] (https://ghc.haskell.org/trac/ghc/ticket/14327) để theo dõi vấn đề này. –
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