I would like to be able to write an IO-action, which would return a polymorphic function, which could be used for different values, but it seems I can't. Can anyone help me doing that please?
f :: a -> Bool
f _ = True
getF :: Int -> (a -> Bool)
getF _ = f
getFIO :: IO (a -> Bool)
getFIO = return f
main :: IO ()
main = do
-- this works
print ((f :: Int -> Bool) (10::Int))
print ((f :: String -> Bool) "asd")
-- this works
let f' = getF 10
print (f' (10::Int))
print (f' "asd")
-- this doesn't
f'' <- getFIO
print (f'' (10::Int))
print (f'' "asd")
-- but this does
f''' <- getFIO
print (f''' (10::Int))
f'''' <- getFIO
print (f'''' "asd")
return ()
Haskell does not allow you to use a polymorphic argument to a type constructor other than ->
. You need to use a newtype
to make use of that special exemption.
{-# LANGUAGE RankNTypes #-}
newtype ToBool = ToBool {getToBool :: forall a . a -> Bool}
f :: ToBool
f = ToBool (const True)
getFIO :: IO ToBool
getFIO = return f
You'll need to apply getToBool
each time you want to use f
, but that's okay.
To complement the other answers, I'd note that
f :: IO (a -> Bool)
actually means
f :: forall a. IO (a -> Bool)
which describes the following contract between caller and callee:
a
f
does some IO
f
returns a value of type a -> Bool
Note that a
is chosen before the IO, hence the last function is monomorphic.
Instead, we need the following type
f :: IO (forall a. a -> Bool)
which postpones the choice of a
after the IO is done. The above type requires the ImpredicativeTypes
extension (which does not really work at the moment in GHC), or using a newtype
wrapper as done in the other answers.
You can make it "work" with RankNTypes
, but then you need a newtype wrapper:
-- might as well be Bool
newtype Pointless = Pointless (forall a. a -> Bool)
getFIO_ :: IO Pointless
getFIO_ = return (Pointless f)
main = do
Pointless f'' <- getFIO_
print (f'' (10::Int))
print (f'' "asd")
So you might be better off rearranging your program to not use that extension, by changing getFIO :: IO Blah
, defining a applyBlah :: Blah -> a -> Bool
, and then using applyBlah f''
where you previously had f''
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.