GHC說我的函數太泛泛,無法作爲參數傳遞。Haskell:將函數作爲參數傳遞時的剛性類型變量錯誤
這裏是一個簡化版本,再現錯誤:
data Action m a = SomeAction (m a)
runAction :: Action m a -> m a
runAction (SomeAction ma) = ma
-- Errors in here
actionFile :: (Action IO a -> IO a) -> String -> IO()
actionFile actionFunc fileName = do
actionFunc $ SomeAction $ readFile fileName
actionFunc $ SomeAction $ putStrLn fileName
main :: IO()
main =
actionFile runAction "Some Name.txt"
這是錯誤說什麼:
• Couldn't match type ‘a’ with ‘()’
‘a’ is a rigid type variable bound by
the type signature for:
actionFile :: forall a. (Action IO a -> IO a) -> String -> IO()
at src/Lib.hs:11:15
Expected type: Action IO a
Actual type: Action IO()
編譯器希望我是我喜歡的類型簽名更具體,但我不能,因爲我需要使用具有不同類型參數的參數函數。就像在我的例子中,我通過它Action IO()
和Action IO String
。
如果我代替(Action IO a -> IO a) -> String -> IO()
爲(Action IO() -> IO()) -> String -> IO()
,如編譯器問,調用與readFile
錯誤,因爲它輸出IO String
。
爲什麼會發生這種情況,我應該怎麼做才能將此函數作爲參數傳遞?
我知道,如果我只是用runAction
裏面我actionFile
功能一切都將正常工作,但在我真正的代碼runAction
是會從IO計算的結果內置了部分應用功能,所以它不是在編譯時間。
你想要一個等級2的類型,但標準的Haskell只允許等級1的類型。啓用'RankNTypes'擴展並將'actionFile'的類型更改爲'(操作IO a - > IO a) - > String - > IO()'。 –
美麗。有用。我將閱讀更多關於類型排名的內容,以瞭解正在發生的事情以及我可能會放棄這種語言擴展的保證。謝謝。 –