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

F. *_*ler 4 monads haskell functional-programming lifting io-monad

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

a :: IO String
b :: IO FilePath
c :: String -> IO String
Run Code Online (Sandbox Code Playgroud)

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

data Configdata = Configdata String FilePath (String -> String)
Run Code Online (Sandbox Code Playgroud)

因此,我不必从IO上下文中获取自己的每个值,而只是从中获取IO Configdata.

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

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

有人有解决方案或解释为什么不可能?我知道使用列表而不是函数是一个选项,但我更愿意使用函数.

lef*_*out 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?o?m ?yo??ur eye?s? ?l?ik?e liq?uid pain"
Run Code Online (Sandbox Code Playgroud)

现在,如果可以将其转换为IO (String -> String),则必须在返回纯函数之前对任何输入执行所有可能的IO操作String -> String.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)
Run Code Online (Sandbox Code Playgroud)

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

  • 如果有一组预定的字符串,那么在集合中为每个字符串创建一个小的自定义类型可能是有意义的.然后Universe包可以给你[`sequenceA ::(Foo - > IO String) - > IO(Foo - > String)`](http://hackage.haskell.org/package/universe-1.0/docs/Data -Universe-Instances-Reverse.html #t:Traversable),它具有您描述的创建"Map"并将其编入索引的行为. (2认同)