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()'。 –
美丽。有用。我将阅读更多关于类型排名的内容,以了解正在发生的事情以及我可能会放弃这种语言扩展的保证。谢谢。 –