Let's figure it out, working from the inside out. Starting from this:
last $ filter (<100) $ [2..] >>= (\a -> if 0 == (length $ filter (== 0) $ map (mod a) $ [2..a-1]) then (return a) else [])
First, consider map (mod a) [2..a-1] . It is just a conversion of the final list, so there is no problem here, and we will ignore it here, putting [..] in its place. Since we only care about completion, any final list is as good as the other.
The same goes for filter (== 0) [...] . This can only shorten the list, so instead we can get an empty list, but definitely a finite one. Therefore, ignore this. Now consider length [..] - we know that the list is finite, so this will end just fine, giving some answer of 0 or more. We will ignore the specific answer and put ? in its place. Still good.
lambda \a -> if 0 == ? then return a else [] \a -> if 0 == ? then return a else [] uses return in the monad of the list, so it replaces a either [a] or [] , which, by the way, is equivalent to Maybe , but that is another matter. Again, we know that a lot will work, so we ignore the details and use \a -> [a?] .
The monadic binding [2..] >>= \a -> [a?] more interesting. (>>=) here is concatMap , and the first argument is an infinite list. Moving each item to a singleton list and concatenating obviously doesn't change anything, while mapping to an empty list removes the item, so it's essentially just a filter . However, itβs not so simple here, because we are filtering an endless list without the obvious certainty that everything will pass the filter. If you execute filter (const False) [0..] , the "result" will not contain any elements, but the calculation will never end; [] at the output of the filter comes from finding the end of the input list, and it does not matter, and since it will never find the first element, the result will be only _|_ .
So, everything is already problematic. The next part, filter (<100) , worsens the situation - we filter elements from a strictly growing list, and then filter it on the basis that it is under some value, so according to the above argument, if we pass by 100 , the result will hang .
And the last insult to last - this list is still endless, but at some point it will be rejected and not create more elements, so when we ask for the last element, we can see that it will not be able to complete the work for several reasons!
What you want to do here is, firstly, apply your knowledge that the list is strictly growing and not filtering the list, just take the prefix to the desired point - for example, takeWhile (<100) , not filter (< 100) . Note that this still diverges if there are no elements greater than 100 as a takeWhile , since takeWhile does not know when to stop.