GHC is saying my function is too general to be passed as an argument.
Here is a simplified version that reproduces the error:
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"
This is what the error says:
• 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 ()
The compiler wants me to be more specific in my type signature, but I can't because I will need to use the parameter function with different types of arguments. Just like in my example I pass it an Action IO ()
and an Action IO String
.
If I substitute (Action IO a -> IO a) -> String -> IO ()
for (Action IO () -> IO ()) -> String -> IO ()
, like the compiler asked, the invocation with readFile
errors because it outputs an IO String
.
Why is this happening and what should I do to be able to pass this function as an argument?
I know that if I just use runAction
inside my actionFile
function everything will work, but in my real code runAction
is a partially applied function that gets built from results of IO computations, so it is not available at compile time.