sequence
работает:
Prelude> sequence (replicate 4 [1,0])
[[1,1,1,1],[1,1,1,0],[1,1,0,1],[1,1,0,0],[1,0,1,1],[1,0,1,0],[1,0,0,1],[1,0,0,0],[0,1,1,1],[0,1,1,0],[0,1,0,1],[0,1,0,0],[0,0,1,1],[0,0,1,0],[0,0,0,1],[0,0,0,0]]
Но сочетание последовательности и реплики уже имеет название:
Prelude> import Control.Monad
Prelude Control.Monad> replicateM 4 [1,0]
[[1,1,1,1],[1,1,1,0],[1,1,0,1],[1,1,0,0],[1,0,1,1],[1,0,1,0],[1,0,0,1],[1,0,0,0],[0,1,1,1],[0,1,1,0],[0,1,0,1],[0,1,0,0],[0,0,1,1],[0,0,1,0],[0,0,0,1],[0,0,0,0]]
Поскольку всю интересную работу выполняет sequence
, давайте рассмотрим ее поближе.
sequence :: Monad m => [m a] -> m [a]
sequence [] = return []
sequence (x:xs) = do
x' <- x
xs' <- sequence xs
return (x':xs')
(Есть более короткие способы написать это, но это самый простой.)
Оказывается, sequence
тоже не содержит никакой интересной логики. Это единственная очевидная функция с такой сигнатурой типа, которая использует весь свой аргумент. Так что настоящая магия должна быть в экземпляре Monad
для []
, я думаю.
instance Monad [] where
return x = [x]
xs >>= f = concatMap f xs
Это просто перекладывает ответственность на concatMap
, но, возможно, теперь это начинает иметь больше смысла..
concatMap :: (a -> [b]) -> [a] -> [b]
concatMap _ [] = []
concatMap f (x:xs) = f x ++ concatMap f xs
Я не уверен, насколько все это помогает, но об этом стоит помнить.
Возможно, более полезным будет специализировать сигнатуру типа от sequence
до m ~ []
:
sequence :: [[a]] -> [[a]]
В данном конкретном случае sequence
лучше было бы переименовать в sequences
. Он создает все последовательности, состоящие из выбора одного элемента из каждого внутреннего списка.
person
Carl
schedule
02.07.2015