當我遇到奇怪的GHC行爲時,我並沒有真正理解,當時我正在展示一位同事Free
。下面是typechecks一個簡單的,做作的程序:當我添加一個無關的定義時,爲什麼在這個程序中會出現類型錯誤?
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()))
我嘗試添加另一種定義,但它並不完全正確:
writeLine :: String -> App()
writeLine line = liftF (InR (WriteLine line()))
的這裏的問題是,我錯過了另一個InL
。正確的定義應該是這樣的:
writeLine :: String -> App()
writeLine line = liftF (InR (InL (WriteLine line())))
但是,這不是重點。對我來說奇怪的是,當我添加第一個不正確的writeLine
的定義時,GHC產生的類型錯誤。具體而言,它產生類型錯誤:
/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()))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
兩個誤差的第二(所述一個上線29)是有意義的。這是我期望的錯誤。但是第26行的錯誤完全讓我感到困惑。 writeFile
的定義是正確的!添加我的writeLine
的錯誤定義不應該對writeFile
有任何影響,對吧?這是怎麼回事?
我能夠在GHC 8.0.2和GHC 8.2.1上重現這一點。我想知道這是否是GHC中的錯誤(所以我可以報告它),或者如果這是我的代碼的問題,我不明白。
哦,這是一個偉大的。注意,如果你把錯誤的'writeLine'定義放在其他定義之後,那麼可疑的錯誤就會消失。 :) – Alec
我已打開[GHC Trac#14327](https://ghc.haskell.org/trac/ghc/ticket/14327)來跟蹤此問題。 –
這個問題似乎與FD有關,因爲專門研究'liftF':: Functor f => f a - > Free f a'擺脫了額外的錯誤。也許我錯過了一些東西。 – Alec