简体   繁体   English

定义haskell函数[IO a]-> IO [a]

[英]Define a haskell function [IO a] -> IO[a]

I am doing a haskell exercise, regarding define a function accumulate :: [IO a] -> IO [a] which performs a sequence of interactions and accumulates their result in a list. 我正在做一次haskell练习,关于定义一个函数accumise :: [IO a]-> IO [a],该函数执行一系列交互并将其结果存储在列表中。

What makes me confused is how to express a list of IO a ? 让我感到困惑的是如何表达IO列表? (action:actions)?? (动作:动作)??

how to write recursive codes using IO?? 如何使用IO编写递归代码?

This is my code, but these exists some problem... 这是我的代码,但是这些存在一些问题...

accumulate :: [IO a] -> IO [a]
accumulate (action:actions) = do 
                                value <- action
                                list <- accumulate (action:actions)
                                return (convert_to_list value list)


convert_to_list:: Num a =>a -> [a]-> [a]
convert_to_list a [] = a:[]
convert_to_list x xs = x:xs

What you are trying to implement is sequence from Control.Monad . 您要实现的是Control.Monad sequence

Just to let you find the answer instead of giving it, try searching for [IO a] -> IO [a] on hoogle (there's a Source link on the right hand side of the page when you've chosen a function). 只是为了让你找到答案,而不是给它,尝试搜索[IO a] -> IO [a]hoogle (有,当你选择了一个功能页面的右手边链接)。

Try to see in your code what happens when list of actions is empty list and see what does sequence do to take care of that. 尝试在代码中查看当动作列表为空列表时会发生什么,并查看序列做了什么来解决这一问题。

There is already such function in Control.Monad and it called sequence (no you shouldn't look at it). Control.Monad已经有这样的函数,它称为sequence (不,您不应该看它)。 You should denote the important decision taken during naming of it. 您应该指出在命名过程中做出的重要决定。 Technically [IO a] says nothing about in which order those Monad s should be attached to each other, but name sequence puts a meaning of sequential attaching. 从技术上讲, [IO a]没有说明这些Monad应该以什么顺序彼此连接,但是名称sequence赋予了顺序连接的含​​义。

As for the solving you problem. 至于解决你的问题。 I'd suggest to look more at types and took advice of @sacundim. 我建议多看一些类型,并建议@sacundim。 In GHCi (interpreter from Glasgow Haskell Compiler) there is pretty nice way to check type and thus understand expression ( :t (:) will return (:) :: a -> [a] -> [a] which should remind you one of you own function but with less restrictive types). 在GHCi(格拉斯哥Haskell编译器的解释器)中,有一种非常不错的方法来检查类型,从而理解表达式( :t (:)将返回(:) :: a -> [a] -> [a] ,这应该提醒您一个您自己的函数,但限制类型较少)。

First of all I'd try to see at what you have showed with more simple example. 首先,我将尝试通过更简单的示例查看您所显示的内容。

data MyWrap a = MyWrap a

accumulate :: [MyWrap a] -> MyWrap [a]
accumulate (action:actions) = MyWrap (convert_to_list value values) where
    MyWrap value = action -- use the pattern matching to unwrap value from action
    -- other variant is:
    -- value = case action of
    --             MyWrap x -> x
    MyWrap values = accumulate (action:actions)

I've made the same mistake that you did on purpose but with small difference ( values is a hint). 我犯了与您有意犯的错误相同的错误,但差异很小( values只是一个提示)。 As you probably already have been told you could try to interpret any of you program by trying to inline appropriate functions definitions. 正如您可能已经被告知的,您可以尝试通过内联适当的函数定义来尝试解释任何程序。 Ie match definitions on the left side of equality sign ( = ) and replace it with its right side. 即,匹配等号( = )左侧的定义,并将其替换为右侧。 In your case you have infinite cycle. 您的情况是无限循环的。 Try to solve it on this sample or your and I think you'll understand (btw your problem might be just a typo). 尝试在这个样本或您的样本上解决它,我想您会明白的(但是您的问题可能只是错字)。

Update: Don't be scary when your program will fall in runtime with message about pattern match. 更新:当您的程序在运行时落入有关模式匹配的消息时,请不要害怕。 Just think of case when you call your function as accumulate [] 当您将函数调用为accumulate []时,请考虑一下情况

可能您正在寻找映射[ma] -> m [a] sequence函数?

So the short version of the answer to your question is, there's (almost) nothing wrong with your code. 因此,对于您的问题的答案的简短版本是,您的代码几乎没有错误。

First of all, it typechecks: 首先,它进行类型检查:

Prelude> let accumulate (action:actions) = do { value <- action ; 
          list <- accumulate (action:actions) ; return (value:list) }
Prelude> :t accumulate
accumulate :: (Monad m) => [m t] -> m [t]

Why did I use return (value:list) there? 为什么在那里使用return (value:list) Look at your second function, it's just (:) . 看第二个函数,它只是(:) Calling g g

g a [] = a:[]
g a xs = a:xs

is the same as calling (:) with the same arguments. 与使用相同参数调用(:)相同。 This is what's known as "eta reduction": (\\x-> gx) === g (read === as "is equivalent"). 这就是所谓的“ eta缩减”: (\\x-> gx) === g (读===为“等价”)。

So now just one problem remains with your code. 所以现在您的代码只剩下一个问题。 You've already taken a value value <- action out of the action, so why do you reuse that action in list <- accumulate (action:actions) ? 您已经从操作中取出了值value <- action ,那么为什么要在list <- accumulate (action:actions)重用该操作? Do you really have to? 你真的必须吗? Right now you have, eg, 现在你有,例如

accumulate [a,b,c]  ===
do { v1<-a; ls<-accumulate [a,b,c]; return (v1:ls) } ===
do { v1<-a; v2<-a; ls<-accumulate [a,b,c]; return (v1:v2:ls) } ===
do { v1<-a; v2<-a; v3<-a; ls<-accumulate [a,b,c]; return (v1:v2:v3:ls) } ===
.....

One simple fix and you're there. 一个简单的修复程序,您就在那里。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM