I found it helpful to define an auxiliary function, partitionsCap, which does not let any of the items be larger than a given value. Used recursively, it can be used to only produce the monotonically decreasing results you want (i.e. no [1,3,1] when you already have [1,1,3]):
partitions :: Int -> [[Int]]
partitions n = partitionsCap n n
partitionsCap :: Int -> Int -> [[Int]]
partitionsCap cap n
| n < 0 = error "partitions: negative number"
| n == 0 = [[]]
| n > 0 = [i : p | i <- [hi,hi-1..1], p <- partitionsCap i (n-i)]
where hi = min cap n
At the heart of the algorithm is the idea that, when partitioning N, you take i from n down to 1, and prepend i to the partitions of n-i. Simplified:
concat [map (i:) $ partitions (n-i) | i <- [n,n-1..1]]
but wrong:
> partitions 3
[[3],[2,1],[1,2],[1,1,1]]
We want that [1,2] to go away. Hence, we need to cap the partitions we're prepending to so they won't go above i:
concat [map (i:) $ partitionsCap i (n-i) | i <- [hi,hi-1..1]]
where hi = min cap n
Now, to clean it up: that concat and map so close together got my attention. A little background: list comprehensions and the list monad are very closely related, and concatMap is the same as >>= with its arguments flipped, in the list monad. So I wondered: can those concat and map somehow turn into a >>=, and can that >>= somehow sweet-talk its way into the list comprehension?
In this case, the answer is yes :-)
[i : p | i <- [hi,hi-1..1], p <- partitionsCap i (n-i)]
where hi = min cap n