Reputation: 11
I'm trying to write some code in Haskell and there is problem that i can't solve
f 0 = []
f n = do
x <- [0..4]
y <- x:(f (n-1))
return y
The output is:
[0,0,0,1,2,3,4,1,0,1,2,3,4,2,0,1,2,3,4,3,0,1,2,3,4,4,0,1,2,3,4,1,0,0,1,2,3,4,1,0,1,2,3,4,2,0,1,2,3,4,3,0,1,2,3,4,4,0,1,2,3,4,2,0,0,1,2,3,4,1,0,1,2,3,4,2,0,1,2,3,4,3,0,1,2,3,4,4,0,1,2,3,4,3,0,0,1,2,3,4,1,0,1,2,3,4,2,0,1,2,3,4,3,0,1,2,3,4,4,0,1,2,3,4,4,0,0,1,2,3,4,1,0,1,2,3,4,2,0,1,2,3,4,3,0,1,2,3,4,4,0,1,2,3,4]
but I need it to be:
[[0,0,0],[0,0,1],[0,0,2],[0,0,3],[0,0,4],[0,1,0],[0,1,1]...
Any ideas?
Upvotes: 1
Views: 104
Reputation: 1477
So you want the elements of your final list to be lists themselves ?
In the List monad, each <-
remove one enclosing from the type, in other words :
(x :: a) <- (xs :: [a])
So it is clear that x :: Int
in your code. And you wish for your function to return [[Int]]
so what should be the type of x:(f (n-1))
? You see that this expression shouldn't typecheck if f
type was correct so there is your problem : you don't want to cons x
to the result of f (n-1)
but to each of the results of f (n-1)
thus :
f n = do
x <- [0..4]
xs <- f (n-1)
return (x : xs)
If you try this you should see it doesn't work, this is because your f 0
should contain one possibility :
f 0 = return [] -- or [[]]
Upvotes: 3
Reputation: 116174
Others have already answered, but you may wish to know there's already a function like yours in the standard library:
> import Control.Monad
> replicateM 3 [0..4]
[[0,0,0],[0,0,1],[0,0,2],[0,0,3],[0,0,4],[0,1,0],[0,1,1], ...
Upvotes: 4
Reputation: 27210
Let's desugar first:
f 0 = []
f n = [0 .. 4] >>= \x -> x : (f (n - 1)) >>= \y -> return y
Note
xs >>= f = concat (map f xs)
[0..4] >>= \x -> x : (f (n - 1))
will simply return [0..4]
when n is 1. However, it need to be [[0], [1], [2], [3], [4]]
,
Thus, the following will do:
f 0 = [[]]
f n = [0 .. 4] >>= \x -> map (x:) (f (n - 1)) >>= \y -> return y
Upvotes: 2