我有以下问题:我的任务是编写一个函数,其中包含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在val之后<.
但这一点也没有帮助,而且会是非常糟糕的风格。我该如何解决这个问题?
我要暗示,没有解决办法,
提前谢谢。
编辑
我编辑它的方式如下:
seqList :: [a -> IO a] -> a -> IO a
seqList [] n = return n
seqList (inter:inters) n = do
val <- inter n
seqList inters val因为seqList指针,val已经是正确的类型了。
这应该可以,还是我弄错了?它实际上适用于我的例子。
我仍然是非常新的,这整个做表示法-单一-io-的东西,因为它看起来。
非常感谢你的暗示。
发布于 2015-05-28 02:36:09
编辑的版本是正确的。
不过,有一种有趣的方法来看待这个问题。可以按以下方式分析该类型
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-notation位。我们还可以更进一步
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如果我们认识到褶皱经常暴露s,那么我们也可以检测到Thing a对于任何a的选择都是一个单样体。
memptyThing :: Thing a
memptyThing = neutralThing
mappendThing :: Thing a -> Thing a -> Thing a
mappendThing = combineThings最后,如果我们真的很聪明的话,我们可以注意到,Thing继承了它的单一性,它是从一个Category-in的稍微一般的结构中继承出来的,这就是所谓的 category。如果我们使用Kleisli类型本身,就会有很多包装和展开,但是我们可以检查来自Control.Monad的return和(>=>)的类型。
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发布于 2015-05-28 04:34:53
另一种思考方法是:如果您有两个这样的操作,您将如何将它们链接在一起? library that does that。应该不难理解:
(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c
f >=> g = \a -> do
b <- f a
g b如果您有那个操作符,那么您可以通过获取操作列表并在所有操作之间放置seqList来编写>=>。 function将完成这一任务;正如文档所述,它正是这样做的:
foldr f z [x1, x2, ..., xn] == x1 `f` (x2 `f` ... (xn `f` z)...)因此,将它们放在一起,加上空列表情况下的return,您将得到:
import Control.Monad ((>=>))
seqList :: [a -> IO a] -> a -> IO a
seqList actions = foldr (>=>) return actions其行为可以用这些方程来描述:
foldr (>=>) return [] == return
foldr (>=>) return [x1, ..., xn] == x1 >=> ... >=> xn >=> return让我们把它做得更详细!foldr的定义如下:
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr _ z [] = z
foldr f z (x:xs) = f x (foldr f z xs)因此,使用它,我们可以重写我对seqList的定义如下:
-- Use the definition of `foldr` to split this into two cases
seqList [] = return
seqList (action:actions) = action >=> foldr (>=>) return actions
-- Use the definition of `>=>` to spell out the second equation
seqList [] = return
seqList (action:actions) = \a -> do
val <- action a
foldr (>=>) return actions val
-- But by the definition of `seqList`, we can rewrite the last line
-- to this:
seqList [] = return
seqList (action:actions) = \a -> do
val <- action a
seqList actions val这就是你第二次尝试时写的!
发布于 2015-05-27 22:12:06
一些提示:
>=>。Endo单半群,特别是它的mconcat签名。尝试在签名中用Endo a替换a -> a。Endo一元泛化的实例
新型EndoM m a= EndoM { appEndoM ::a -> m a}
看起来像?它的mempty和mappend是什么?它的mconcat是什么?https://stackoverflow.com/questions/30493159
复制相似问题