1

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.

What makes me confused is how to express a list of IO a ? (action:actions)??

how to write recursive codes using 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
1
  • 3
    I really don't see many ways to give a hint that doesn't give the whole problem away. I just recommend you look at it harder and try more ideas. I will just say one thing: the point of recursive solutions is to reduce a problem to a smaller instance of itself, and your list <- accumulate (action:actions) line is not doing that. Also, your convert_to_list function is unnecessary. Commented Sep 30, 2012 at 6:19

4 Answers 4

5

What you are trying to implement is sequence from Control.Monad.

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).

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.

Sign up to request clarification or add additional context in comments.

6 Comments

I'd not suggest reading of that particular source of sequence since it uses foldr with additional helper function. This might be written easier (of course less optimized for inlining or whatever they've tried to do).
I find the source of sequence most readable and instead of just getting the answer from someone without having the basics clear is not the right approach. I think if you know about foldr then there is nothing which you will not understand in the definition of sequence.
I think understanding using of foldr and any pointfree code is usually much harder for those who just start touching Haskell without any similar background. Tapping onto problems and solving them by self gives better understanding of what happens. What I understand with source of sequence I've told already. What I don't understand is what you mean under "answer from someone without having the basics clear"?
@ony I meat that if you dont understand map and fold then you should first learn them before trying to copy some code from somewhere or asking someone about certain task you want to do.
I wouldn't be so sure. Before learning map you usually learn how to create recursive functions and learns how they works rather than starts writing something like fib = 1 : 1 : zipWith (+) fib (tail fib), accum = foldr (liftA2 (:)) (pure []), fact = (product . enumFromTo 1), fib = 1 : scanl (+) 1 fib etc. map and foldl that's high-order functions and they usually comes after recursion in books.
|
2

There is already such function in Control.Monad and it called sequence (no you shouldn't look at it). You should denote the important decision taken during naming of it. Technically [IO a] says nothing about in which order those Monads should be attached to each other, but name sequence puts a meaning of sequential attaching.

As for the solving you problem. I'd suggest to look more at types and took advice of @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).

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). As you probably already have been told you could try to interpret any of you program by trying to inline appropriate functions definitions. I.e. 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 []

Comments

1

Possibly you looking for sequence function that maps [m a] -> m [a]?

1 Comment

I suspect that's a homework and putting accumulate = sequence would not be an answer ;)
1

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? Look at your second function, it's just (:). Calling 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-> g x) === g (read === as "is equivalent").

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)? Do you really have to? Right now you have, e.g.,

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.