首先,我會將理解翻譯爲單調錶達式。
x >>= \i -> x >>= \j -> x >>= \k -> x >>= \l -> return [i,j,k,l]
隨着n = 4
我們看到我們有4 x
的,一般都會有n
x
的。因此,我在考慮長度爲n
的x
的列表。
[x,x,x,x] :: [[a]]
我們該如何從[x,x,x,x]
轉到monadic表達式?第一個好的猜測是foldr
,因爲我們想要對列表中的每個元素進行一些操作。特別是,我們希望從每個x
中獲取一個元素並用這些元素形成一個列表。
foldr :: (a -> b -> b) -> b -> [a] -> b
-- Or more accurately for our scenario:
foldr :: ([a] -> [[a]] -> [[a]]) -> [[a]] -> [[a]] -> [[a]]
有兩個方面拿出了foldr相似,我會打電話f :: [a] -> [[a]] -> [[a]]
和z :: [[a]]
。我們知道什麼是foldr f z [x,x,x,x]
:
foldr f z [x,x,x,x] = f x (f x (f x (f x z)))
如果加上括號前面的一元表達,我們有這樣的:
x >>= \i -> (x >>= \j -> (x >>= \k -> (x >>= \l -> return [i,j,k,l])))
你可以看到兩個表達式是如何尋找相似。我們應該能夠找到一個f
和z
使它們相同。如果我們選擇f = \x a -> x >>= \x' -> a >>= \a' -> return (x' : a')
我們得到:
f x (f x (f x (f x z)))
= (\x a -> a >>= \a' -> x >>= \x' -> return (x' : a')) x (f x (f x (f x z)))
= f x (f x (f x z)) >>= \a' -> x >>= \x' -> return (x' : a')
= f x (f x (f x z)) >>= \a' -> x >>= \l -> return (l : a')
= (f x (f x z) >>= \a' -> x >>= \k -> return (k : a')) >>= \a' -> x >>= \l -> return (l : a')
= f x (f x z) >>= \a' -> x >>= \k -> x >>= \l -> return (l : k : a')
- 請注意,我已經逆轉
i,j,k,l
順序l,k,j,i
但在尋找組合的情況下,這應該是不相關的。如果真的擔心,我們可以試試a' ++ [x']
。
的最後一步是因爲(a >>= \b -> c) >>= \d -> e
相同a >>= \b -> c >>= \d -> e
(佔可變衛生時)和return a >>= \b -> c
相同(\b -> c) a
。
如果我們繼續展開這個表達式,最終我們將在前面達到z >>= \a' -> …
。這裏唯一有意義的選擇是z = [[]]
。這意味着foldr f z [] = [[]]
可能並不理想(改爲[]
)。相反,我們可能使用foldr1
(對於非空列表,我們可能使用Data.NonEmpty
),或者我們可能會爲空列表添加一個單獨的子句到combs
。
看着f = \x a -> x >>= \x' -> a >>= \a' -> return (x' : a')
我們可能會意識到這種有用的等價性:a >>= \b -> return (c b) = c <$> a
。因此,f = \x a -> x >>= \x' -> (x' :) <$> a
。然後還有a >>= \b -> c (g b) = g <$> a >>= \b -> c
等f = (:) <$> x >>= \x' -> x' <$> a
。最後,a <*> b = a >>= \x -> x <$> b
等等f = (:) <$> x <*> a
。
The official implementationsequenceA
列表是foldr (\x a -> (:) <$> x <*> a) (pure [])
,正是我們在這裏想到的。這可以進一步縮短爲foldr (liftA2 (:)) (pure [])
,但可能存在一些優化差異,使得實現者不選擇此選項。
最後一步是僅僅想出一個n
x
的列表。這只是replicatereplicate n x
。碰巧有一個既有複製又有排序的功能,叫做replicateMreplicateM n x
。
您可以先提供目標。你想在這裏做什麼? –
@WillemVanOnsem給定數字n和一組字符x,從長度爲n的x生成符號的每個組合。例如x =「abc」和n = 2會給出[「aa」,「ab」,「ac」,「ba」,「bb」,「bc」,「ca」,「cb」,「cc」] 。 – Stewart
列表解析對於某些單點操作來說實際上是一個很好的捷徑。 (事實上,有一個GCH擴展允許一個生成器是一個任意的monad,而不僅僅是一個列表。)但是,你不應該將它們視爲執行它們的方式。 – chepner