我希望能够编写一个IO动作,它将返回一个多态函数,可以用于不同的值,但似乎我不能.有人可以帮我这样做吗?
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 ()
Run Code Online (Sandbox Code Playgroud)
Haskell不允许您对类型构造函数使用多态参数->.您需要使用a newtype来使用该特殊豁免.
{-# LANGUAGE RankNTypes #-}
newtype ToBool = ToBool {getToBool :: forall a . a -> Bool}
f :: ToBool
f = ToBool (const True)
getFIO :: IO ToBool
getFIO = return f
Run Code Online (Sandbox Code Playgroud)
getToBool每次你想要使用时都需要申请f,但没关系.
为了补充其他答案,我会注意到
f :: IO (a -> Bool)
Run Code Online (Sandbox Code Playgroud)
实际意味着
f :: forall a. IO (a -> Bool)
Run Code Online (Sandbox Code Playgroud)
它描述了调用者和被调用者之间的以下契约:
af做一些IOf返回一个类型的值a -> Bool注意,a在IO之前选择,因此最后一个函数是单态的.
相反,我们需要以下类型
f :: IO (forall a. a -> Bool)
Run Code Online (Sandbox Code Playgroud)
这推迟了aIO完成后的选择.上面的类型需要ImpredicativeTypes扩展(在GHC中当前不能正常工作),或者使用newtype其他答案中的包装器.