```
-- | Combinations

module Math.Combinat.Combinations where

import Math.Combinat.Helper

-------------------------------------------------------

-- | Combinations fitting into a given shape and having a given degree.
--   The order is lexicographic, that is,
--
-- > sort cs == cs where cs = combinations' shape k
--
combinations'
:: [Int]         -- ^ shape
-> Int           -- ^ sum
-> [[Int]]
combinations' [] 0 = [[]]
combinations' [] _ = []
combinations' shape@(s:ss) n =
[ x:xs | x <- [0..min s n] , xs <- combinations' ss (n-x) ]

countCombinations' :: [Int] -> Int -> Integer
countCombinations' [] 0 = 1
countCombinations' [] _ = 0
countCombinations' shape@(s:ss) n = sum
[ countCombinations' ss (n-x) | x <- [0..min s n] ]

-- | All combinations fitting into a given shape.
allCombinations' :: [Int] -> [[[Int]]]
allCombinations' shape = map (combinations' shape) [0..d] where d = sum shape

-- | Combinations of a given length.
combinations
:: Int       -- ^ length
-> Int       -- ^ sum
-> [[Int]]
combinations len d = combinations' (replicate len d) d

-- | # = \\binom { len+d-1 } { len-1 }
countCombinations :: Int -> Int -> Integer
countCombinations len d = binomial (len+d-1) (len-1)

-- | Positive combinations of a given length.
combinations1
:: Int       -- ^ length
-> Int       -- ^ sum
-> [[Int]]
combinations1 len d
| len > d = []
| otherwise = map plus1 \$ combinations len (d-len)
where
plus1 = map (+1)

countCombinations1 :: Int -> Int -> Integer
countCombinations1 len d = countCombinations len (d-len)

-------------------------------------------------------
```