Haskell sequencelistIO [a -> IO a] -> a -> IO a

标签 haskell io monads

我有以下问题: 我的任务是编写一个函数,获取 IO 交互列表和初始值。第一个操作将初始值作为参数,函数应将其结果(IO a)作为参数传递给下一个交互。

后者需要类型 a 的数据,而不是 IO a。 我不知道如何克服这个障碍。

这是我所拥有的:

seqList :: [a -> IO a] -> a -> IO a
seqList [] n = return n
seqList (inter:inters) n = do
        val <- inter n
        return $ seqList inters val

问题在于 val 的类型为 (IO a),但下一个 IO 需要 a。 我尝试过类似的事情

tmp <- unsafePerformIO val

验证后<- ...

但这没有帮助,而且风格非常糟糕。 我该如何解决这个问题?

我想要提示,没有解决方案,

提前致谢。

编辑

我按以下方式编辑它:

seqList :: [a -> IO a] -> a -> IO a
seqList [] n = return n
seqList (inter:inters) n = do
            val <- inter n
            seqList inters val

因为 seqList inters val 已经是正确的类型。

这应该没问题还是我弄错了?它实际上适用于我的示例。

看起来我对整个 do-notation-monads-io-stuff 仍然很陌生。

非常感谢您的提示。

最佳答案

编辑后的版本正确。


不过,有一种有趣的方式来看待这个问题。人们可以如下分析类型

type Thing a = a -> IO a

seqList :: [Thing a] -> Thing a

换句话说,seqList是一种组合Thing的机制。如果我们稍微重写您的工作代码,我们可以强调这一点。

seqList :: [Thing a] -> Thing a
seqList [] n = neutralThing n
seqList (thingHere : restOfThings) n = do
  let remainingThing = seqList restOfThings
  val <- thingHere
  remainingThing val

neutralThing :: Thing a
neutralThing a = return a

特别是,我隔离了三个部分

  • 输入列表为空时返回的中性事物
  • 从列表尾部计算“剩余内容”的递归位
  • “组合”事物的实际 do 表示法位。

我们可以走得更远

seqList :: [Thing a] -> Thing a
seqList [] = neutralThing
seqList (thingHere : restOfThings) = 
  combineThings thingHere (seqList restOfThings)

neutralThing :: Thing a
neutralThing a = return a

combineThings :: Thing a -> Thing a -> Thing a
combineThings thing1 thing2 n = do
  n'  <- thing1 n
  n'' <- thing2 n'
  return n''

现在我们可以识别一个通用模式:seqList 只是列表的折叠。

seqList :: [Thing a] -> Thing a
seqList = foldr combineThings neutralThing

如果我们认识到折叠经常暴露 Monoids我们还可以检测 Thing a 对于任何 a

的选择如何是一个幺半群
memptyThing :: Thing a
memptyThing = neutralThing

mappendThing :: Thing a -> Thing a -> Thing a
mappendThing = combineThings

最后,如果我们真的很聪明,我们可以注意到 Thing 从稍微更通用的 Category 结构中继承了幺半群性。 - 特别是,称为 Kleisli IO category 的东西。如果我们使用 Kleisli 类型本身,将会有大量的包装和展开,但我们可以检查 return(>=> 的类型) 来自 Control.Monad

return :: Monad m => a -> m a
(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c)

稍加注意,我们就可以看到这些类型与 memptyThingmappendThing 兼容。因此,您的问题的最终解决方案如下

seqList :: [Thing a] -> Thing a
seqList = foldr (>=>) return

如果我们愿意的话,我们终于可以注意到它有一个更通用的类型

seqList :: Monad m => [a -> m a] -> (a -> m a)
seqList = foldr (>=>) return

关于Haskell sequencelistIO [a -> IO a] -> a -> IO a,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30493159/

相关文章:

go - 从 io.Writer 写的内容中读取内容

file - Lua 文件处理

c# - 将委托(delegate)序列的复杂交互链接在一起

haskell - 免费单子(monad)函数和仿函数定点之间的区别?

haskell - 多态类型的显式类型签名。第二部分

haskell - haskell如何确定隐式foralls中类型变量的顺序?

linux - Linux/Unix I/O 类型

haskell - 将 GADT 与 DataKinds 用于函数中的类型级数据构造函数约束

haskell - 我如何在 haskell 中抽象这个模式?

haskell - 使用 QuickCheck 自定义可测试实例