我有以下问题: 我的任务是编写一个函数,获取 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
如果我们认识到折叠经常暴露 Monoid
s我们还可以检测 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)
稍加注意,我们就可以看到这些类型与 memptyThing
和 mappendThing
兼容。因此,您的问题的最终解决方案如下
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/