首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >哈斯克尔sequencelistIO [a -> IO a] -> a -> IO a

哈斯克尔sequencelistIO [a -> IO a] -> a -> IO a
EN

Stack Overflow用户
提问于 2015-05-27 21:07:01
回答 3查看 178关注 0票数 2

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

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

以下是我所拥有的:

代码语言:javascript
复制
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。

代码语言:javascript
复制
tmp <- unsafePerformIO val

在val之后<.

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

我要暗示,没有解决办法,

提前谢谢。

编辑

我编辑它的方式如下:

代码语言:javascript
复制
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-的东西,因为它看起来。

非常感谢你的暗示。

EN

回答 3

Stack Overflow用户

发布于 2015-05-28 02:36:09

编辑的版本是正确的。

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

代码语言:javascript
复制
type Thing a = a -> IO a

seqList :: [Thing a] -> Thing a

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

代码语言:javascript
复制
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位。

我们还可以更进一步

代码语言:javascript
复制
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仅仅是列表的一倍。

代码语言:javascript
复制
seqList :: [Thing a] -> Thing a
seqList = foldr combineThings neutralThing

如果我们认识到褶皱经常暴露s,那么我们也可以检测到Thing a对于任何a的选择都是一个单样体。

代码语言:javascript
复制
memptyThing :: Thing a
memptyThing = neutralThing

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

最后,如果我们真的很聪明的话,我们可以注意到,Thing继承了它的单一性,它是从一个Category-in的稍微一般的结构中继承出来的,这就是所谓的 category。如果我们使用Kleisli类型本身,就会有很多包装和展开,但是我们可以检查来自Control.Monadreturn(>=>)的类型。

代码语言:javascript
复制
return :: Monad m => a -> m a
(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c)

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

代码语言:javascript
复制
seqList :: [Thing a] -> Thing a
seqList = foldr (>=>) return

最后,我们可以注意到,如果我们愿意的话,它有一个更一般的类型。

代码语言:javascript
复制
seqList :: Monad m => [a -> m a] -> (a -> m a)
seqList = foldr (>=>) return
票数 2
EN

Stack Overflow用户

发布于 2015-05-28 04:34:53

另一种思考方法是:如果您有两个这样的操作,您将如何将它们链接在一起? library that does that。应该不难理解:

代码语言:javascript
复制
(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c
f >=> g = \a -> do
    b <- f a
    g b

如果您有那个操作符,那么您可以通过获取操作列表并在所有操作之间放置seqList来编写>=> function将完成这一任务;正如文档所述,它正是这样做的:

代码语言:javascript
复制
foldr f z [x1, x2, ..., xn] == x1 `f` (x2 `f` ... (xn `f` z)...)

因此,将它们放在一起,加上空列表情况下的return,您将得到:

代码语言:javascript
复制
import Control.Monad ((>=>))

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

其行为可以用这些方程来描述:

代码语言:javascript
复制
foldr (>=>) return [] == return
foldr (>=>) return [x1, ..., xn] == x1 >=> ... >=> xn >=> return

让我们把它做得更详细!foldr的定义如下:

代码语言:javascript
复制
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr _ z [] = z
foldr f z (x:xs) = f x (foldr f z xs)

因此,使用它,我们可以重写我对seqList的定义如下:

代码语言:javascript
复制
-- 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

这就是你第二次尝试时写的!

票数 2
EN

Stack Overflow用户

发布于 2015-05-27 22:12:06

一些提示:

  • 考虑一下列表中有两个函数的情况,并查看一下>=>
  • 看看Endo单半群,特别是它的mconcat签名。尝试在签名中用Endo a替换a -> a
  • Endo一元泛化的实例 新型EndoM m a= EndoM { appEndoM ::a -> m a} 看起来像?它的memptymappend是什么?它的mconcat是什么?
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30493159

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档