Skip to content

Instantly share code, notes, and snippets.

@jml
Created January 29, 2016 19:51
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jml/cdb20d02cf1195c03f72 to your computer and use it in GitHub Desktop.
Save jml/cdb20d02cf1195c03f72 to your computer and use it in GitHub Desktop.
parts s = do
a <- [1..s-1]
b <- [1..s-a]
c <- [1..s-a-b]
d <- [1..s-a-b-c]
return [a, b, c, d]
@PiDelport
Copy link

Bonus solution: StateT and []

There's a different approach to this problem, using the StateT monad transformer with [].

This combination can be viewed as enriching each alternative value with a state, or as extending state actions to be "state multi-actions".

This lets lets us define a "multi-action" that reads the current sum, and then splits itself into alternatives, one for each possible selection and remaining sum:

import Control.Monad.Trans.Class
import Control.Monad.Trans.State

part :: (Enum n, Num n) => StateT n [] n
part = do s <- get
         d <- lift [1..s]
         put (s-d)
         return d

With this defined, we can implement partsOf simply by repeating part with replicateM, and feeding it the initial sum:

-- We can simply repeat the the part action.
partsOf :: (Enum n, Num n) => Int -> n -> [[n]]
n `partsOf` s = replicateM n part `evalStateT` s

For allPartsOf, we need something that conditionally repeats the action until the state (remaining sum) hits 0. We could implement this ourselves, but conveniently, monad-loops already has whileM, which repeats a monadic value until a monadic condition is met:

import Control.Monad.Loops (whileM)

allPartsOf :: (Enum n, Num n, Ord n) => n -> [[n]]
allPartsOf s = whileM ((0 <) <$> get) part `evalStateT` s

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment