2016-08-18 51 views
4

我有,如IO上下文几个数据类型:转型(一 - > IO b)至10(一 - > B)

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不给我任何能够做到这一点的功能。

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

有人有解决方案或解释为什么它不可能吗? 我知道使用列表而不是函数是一个选项,但是我希望尽可能使用函数。

+14

这不是真的兼容。在'String - > IO String'中,IO计算可以取决于参数,在'IO(String - > String)'它不能。 – Bergi

+1

@Bergi完美地表达了它。这是Applicative和Monad之间的主要区别。 – user2297560

回答

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。即使你只是计划将这个功能用于小猫观看的目的,它也会导致核浩劫。

尽管如此,对于您的特定应用来说,可以做到这一点。特别是,如果您知道函数只会被调用一组预定义的字符串,则可以从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) 

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

+2

如果有一组预定义的字符串,则可以在该集合中为每个字符串创建一个具有一个值的小型自定义类型。然后宇宙包可以给你['sequenceA ::(Foo-> IO String) - > IO(Foo-> String)'](http://hackage.haskell.org/package/universe-1.0/docs/Data -Universe-Instances-Reverse.html#t:Traversable),它具有您描述的创建“Map”并将其编入索引的行为。 –

相关问题