将(a - > IO b)转换为IO(a - > b)

时间:2016-08-18 12:11:34

标签: haskell functional-programming monads io-monad lifting

我在IO上下文中有几种数据类型,如:

a :: IO String
b :: IO FilePath
c :: String -> IO String

我想将它们放在一个数据对象中,如:

data Configdata = Configdata String FilePath (String -> String)

所以我不必从IO上下文中获取自己的每个值,但只是IO Configdata之外。

我没有解决方案的关键点是如何将String -> IO String转换为IO (String -> String)。 Hoogle没有给我任何能够做到这一点的功能。

我不确定它是否可能甚至不可能,因为函数的输入可能是无限的。

有人有解决方案或解释为什么不可能? 我知道使用列表而不是函数是一个选项,但如果可能的话我更喜欢使用函数。

1 个答案:

答案 0 :(得分:10)

确实这是不可能的。考虑一下这个功能:

import Acme.Missiles

boo :: String -> IO String
boo "cute" = return "Who's a nice kitty?"
boo "evil" = launchMissiles >> return "HTML tags lea͠ki̧n͘g fr̶ǫm ̡yo​͟ur eye͢s̸ ̛l̕ik͏e liq​uid pain"

现在,如果可以将其转换为IO (String -> String),则必须在返回纯String -> String函数之前执行all possible IO actions for any input。 IOW,即使你只是计划将这个功能用于观看小猫的目的,也会引发核浩劫。

尽管如此,很可能为您的特定应用执行此操作。特别是,如果您知道只为一组预定的字符串调用该函数,您可以从IO预先查询它们并将结果存储在一个映射中,然后可以将其纯粹编入索引。

import qualified Data.Map as Map

puh :: IO (String -> String)
puh = fmap ((Map.!) . Map.fromList) . forM ["cute"] $ \q -> do
       res <- boo q
       return (q, res)

当然,这在性能方面可能并不可行。