Reputation: 592
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
Upvotes: 1
Views: 592
Reputation: 71070
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.
Upvotes: 1
Reputation: 11208
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.
Upvotes: 5
Reputation: 13223
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 Monad
s 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 []
Upvotes: 2