Przydało mi się zdefiniowanie funkcji pomocniczej, partitionsCap
, która nie pozwala, aby którykolwiek z elementów był większy od podanej wartości. Używane rekursywnie, może być stosowane tylko do wytworzenia monotonically wynikiem malejących chcesz (to znaczy nie [1,3,1]
gdy masz już [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
W sercu algorytmu jest pomysł, że gdy partycjonowanie N, bierzesz i
z n
w dół do 1 i dodajesz i
do partycji n-i
. Uproszczone:
concat [map (i:) $ partitions (n-i) | i <- [n,n-1..1]]
ale źle:
> partitions 3
[[3],[2,1],[1,2],[1,1,1]]
Chcemy że [1,2]
odejść.Stąd musimy cap partycje jesteśmy poprzedzenie się tak, że nie pójdzie powyżej i
:
concat [map (i:) $ partitionsCap i (n-i) | i <- [hi,hi-1..1]]
where hi = min cap n
Teraz, aby go oczyścić: że concat i mapa tak blisko siebie moją uwagę . Trochę tła: spisane ze zrozumieniem listy i monada z listy to very closely related, a concatMap jest tym samym, co >>=
z odwróconymi argumentami na liście monad. Tak więc zastanawiałem się: czy te dane mogą w jakiś sposób przekształcić się w >>=
, w jakiś sposób słodko-gadający sposób na zrozumienie listy?
W tym przypadku odpowiedź brzmi tak :-)
[i : p | i <- [hi,hi-1..1], p <- partitionsCap i (n-i)]
where hi = min cap n
odsunął zmienił który zginął w słupek –
i znowu. @dave, dlaczego próbujesz usunąć oba pytania? :/ –