मुझे एक सहायक फ़ंक्शन, partitionsCap
परिभाषित करने में मदद मिली, जो किसी भी आइटम को दिए गए मान से बड़ा नहीं होने देता है। रिकर्सिवली प्रयुक्त, यह केवल करने के लिए इस्तेमाल किया जा सकता monotonically परिणाम घटते आप चाहते हैं का उत्पादन (यानी कोई [1,3,1]
आप पहले से ही [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
एल्गोरिथ्म के केंद्र में विचार है कि, जब विभाजन है एन, n
से 1 तक नीचे ले जाएं, और n-i
के विभाजन में i
प्रीपेड करें। सरलीकृत:
concat [map (i:) $ partitions (n-i) | i <- [n,n-1..1]]
लेकिन गलत:
> partitions 3
[[3],[2,1],[1,2],[1,1,1]]
हम उस [1,2]
दूर जाना चाहते हैं।इसलिए, हम i
ऊपर विभाजन हम तो वे नहीं जाना होगा करने के लिए prepending रहे हैं टोपी की जरूरत है: अब
concat [map (i:) $ partitionsCap i (n-i) | i <- [hi,hi-1..1]]
where hi = min cap n
, यह साफ करने के लिए ऊपर: कि concat और नक्शा इतने करीब एक साथ मेरा ध्यान मिल गया । एक छोटी सी पृष्ठभूमि: सूची की समझ और सूची मोनड very closely related हैं, और concatMap>>=
जैसा ही है, इसके मोनैड सूची में, इसके तर्क फ़्लिप किए गए हैं। तो मैंने सोचा: क्या concat और मानचित्र किसी भी तरह >>=
में बदल सकता है, और क्या >>=
किसी भी तरह से सूची समझ में अपना रास्ता मिल सकता है?
इस मामले में, जवाब है हां
[i : p | i <- [hi,hi-1..1], p <- partitionsCap i (n-i)]
where hi = min cap n
वापस लुढ़का संपादित करें जो बाद –
और फिर हत्या कर दी है :-)। @ डेव, आप अपने दोनों प्रश्नों को हटाने का प्रयास क्यों कर रहे हैं? :/ –