Ответ 1
powerset :: [a] -> [[a]]
powerset xs = filterM (\x -> [True, False]) xs
------------- -----
filterM :: Monad m => (a -> m Bool ) -> [a] -> m [a]
-- filter :: (a -> Bool ) -> [a] -> [a] (just for comparison)
------------- -----
m Bool ~ [Bool] m ~ []
Так что это filter
"в" монаде недетерминизма (списка).
Обычно фильтр сохраняет в своем входном списке только те элементы, для которых содержит предикат.
Недетерминистически, мы получаем все возможности для сохранения элементов, для которых может храниться недетерминированный предикат, и удаления тех элементов, для которых он может не сохраняться. Здесь это так для любого элемента, поэтому мы получаем все возможности сохранить или удалить элемент.
Который является powerset.
Другой пример (в другой монаде), основанный на том, что упоминается в комментариях в блоге Brent Yorgey,
>> filterM (\x-> if even x then Just True else Nothing) [2,4..8]
Just [2,4,6,8]
>> filterM (\x-> if even x then Just True else Nothing) [2..8]
Nothing
>> filterM (\x-> if even x then Just True else Just False) [2..8]
Just [2,4,6,8]
Давайте посмотрим, как это на самом деле достигается с помощью кода. Мы определим
filter_M :: Monad m => (a -> m Bool) -> [a] -> m [a]
filter_M p [] = return []
filter_M p (x:xs) = p x >>= (\b ->
if b
then filter_M p xs >>= (return . (x:))
else filter_M p xs )
Записывая определения монады списка для return
и bind (>>=
) (т.е. return x = [x]
, xs >>= f = concatMap f xs
), это становится
filter_L :: (a -> [Bool]) -> [a] -> [[a]]
filter_L p [] = [[]]
filter_L p (x:xs) -- = ('concatMap' p x) (\b->
-- (if b then map (x:) else id) $ filter_L p xs )
-- which is semantically the same as
-- map (if b then (x:) else id) $ ...
= [ if b then x:r else r | b <- p x, r <- filter_L p xs ]
Следовательно,
-- powerset = filter_L (\_ -> [True, False])
-- filter_L :: (a -> [Bool] ) -> [a] -> [[a]]
powerset :: [a] -> [[a]]
powerset [] = [[]]
powerset (x:xs)
= [ if b then x:r else r | b <- (\_ -> [True, False]) x, r <- powerset xs ]
= [ if b then x:r else r | b <- [True, False], r <- powerset xs ]
= map (x:) (powerset xs) ++ powerset xs -- (1)
-- or, with different ordering of the results:
= [ if b then x:r else r | r <- powerset xs, b <- [True, False] ]
= powerset xs >>= (\r-> [True,False] >>= (\b-> [x:r|b] ++ [r|not b]))
= powerset xs >>= (\r-> [x:r,r])
= concatMap (\r-> [x:r,r]) (powerset xs) -- (2)
= concat [ [x:r,r] | r <- powerset xs ]
= [ s | r <- powerset xs, s <- [x:r,r] ]
и таким образом мы вывели две обычные реализации функции powerset
.
Перевернутый порядок обработки становится возможным благодаря тому факту, что предикат является константой (const [True, False]
). В противном случае тест будет оцениваться снова и снова для одного и того же входного значения, и мы, вероятно, этого не хотим.