能够从Haskell中的monadic动作获得多态函数

时间:2015-10-19 17:10:07

标签: haskell

我希望能够编写一个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 ()

3 个答案:

答案 0 :(得分:8)

Haskell不允许您对->以外的类型构造函数使用多态参数。您需要使用newtype来使用该特殊豁免。

{-# LANGUAGE RankNTypes #-}
newtype ToBool = ToBool {getToBool :: forall a . a -> Bool}

f :: ToBool
f = ToBool (const True)

getFIO :: IO ToBool
getFIO = return f

每次要使用getToBool时,您都需要申请f,但这没关系。

答案 1 :(得分:5)

为了补充其他答案,我注意到了

f :: IO (a -> Bool)

实际上意味着

f :: forall a. IO (a -> Bool)

描述了来电者和被叫者之间的以下合同:

  1. 来电者选择类型a
  2. 然后,f执行了一些IO
  3. 最后,f返回a -> Bool
  4. 类型的值

    请注意,在IO之前选择a,因此最后一个函数是单态的。

    相反,我们需要以下类型

    f :: IO (forall a. a -> Bool)
    

    在IO完成后推迟了a的选择。上述类型需要ImpredicativeTypes扩展名(目前在GHC中不起作用),或者使用newtype包装器,如其他答案中所做的那样。

答案 2 :(得分:4)

你可以使用RankNTypes“工作”,但是你需要一个newtype包装器:

-- 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")

因此,您可能最好重新安排程序,以便不使用该扩展程序,更改getFIO :: IO Blah,定义applyBlah :: Blah -> a -> Bool,然后使用之前applyBlah f'' f'' }。

相关问题