【问题标题】:Transformation of (a -> IO b) to IO (a -> b)(a -> IO b) 到 IO (a -> b) 的转换
【发布时间】:2016-08-18 12:11:33
【问题描述】:

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

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

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

【问题讨论】:

  • 这不是真的兼容。在String -> IO String 中,IO 计算可以依赖于参数,在IO (String -> String) 中则不能。
  • @Bergi 完美地说明了这一点。这是 Applicative 和 Monad 之间的主要区别。
  • stackoverflow.com/q/18890408 的可能重复项。

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


【解决方案1】:

这确实是不可能的。考虑函数:

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)

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

【讨论】:

  • 如果有一组预先确定的字符串,那么创建一个小的自定义类型可能是有意义的,其中每个字符串都有一个值。然后,Universe 包可以为您提供 sequenceA :: (Foo -&gt; IO String) -&gt; IO (Foo -&gt; String),它具有您描述的创建 Map 并对其进行索引的行为。
猜你喜欢
  • 1970-01-01
  • 2021-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多