Reputation: 35
I'm working with some code and there seems to be an issue which I can't figure out.
So I've got a method which decrements an input Int by 1 until it hits 5. (I know if i enter less than 1 it would cause an error but i will fix that later)
I have a second function which calls a takes a List as a parameter which calls this function and returns the list of numbers, I want to call length on this list and populate a separate list (I'm not the best at explaining, i'll show with code examples below)
sub 5 = return [1]
sub x =
do
xs <- sub (x - 1)
return (x:xs)
f xs = [ length (sub x) | x<-xs ]
If I call sub 10 on it's own it gives the output [10,9,8,7,6,1], however if I call length on this, it gives the output [1].
In my head i thought the output would be 6, as it has 6 elements in.
Does anyone have any idea why this is happening and/or a way to fix it?
Thanks in advance.
Upvotes: 0
Views: 558
Reputation: 22596
sub doesn't return [10,9,8,6,1]
but [[10,9,8,6,1]]
(a list of list) therefore the length is 1. You don't need the return. You are in a list monad, return
wraps it's value into a list, this why you end up with nested list. Your code should be
sub 5 = [1] -- or return 1
sub x = do
let xs = sub (x -1)
(x:xs)
Upvotes: 2
Reputation: 1477
The problem is that this sub function is written like you were in an imperative language and that return doesn't mean the same thing in Haskell : it means "wrap this thing in a Monad (which Monad depends on the context)". Here since you use length on the result of sub the list [] monad is used and the result is [ [10, 9, 8, 7, 6, 5] ] a list of one element which happen to be a list of 6 elements. mb14 correctly identified that but then corrected only the first case of your function, the second case is also monadic but shouldn't be...
sub 5 = [1]
sub x = x : sub (x - 1)
is the simple code you should be using, you don't need any monad here...
Upvotes: 2