2012-05-06 2 views
2

У меня есть следующиеHaskell Monadic Операции на списках

[3,2,1] >> [1] 
= [1,1,1] 

Я не в полной мере понять, почему это происходит? Глядя на >> Я ожидал бы [3,2,1], но я вижу, что это разные по спискам.

Может ли кто-нибудь объяснить, почему?

+0

Подумайте, что произойдет, если монада 'IO' поступила бы по аналоговому пути ...' putStr «Привет,» >> putStr «world» 'будет действием, которое печатает _only_' "world". – leftaroundabout

+0

Это может помочь, если вы объясните, почему вы ожидаете результатов, которые вы предложили. –

+0

@leftaroundabout: Подумайте о типе '(>>) :: Monad m => m a -> m b -> m b'. В терминах «IO» это будет «объединить два действия типа« IO a »и« IO b »соответственно и произвести действие типа« IO b ». Подумайте о '(getLine >> getLine) :: IO String': он считывает две строки со стандартного ввода, отбрасывает результат чтения первой строки и возвращает результат чтения второй строки. Аналогичная вещь для '([3,2,1] >> [" Hello "," World "]) :: [String]': выберите число, затем выберите строку и верните строку, которая неявно отбрасывает число , –

ответ

7

>> может быть определена следующим образом:

ma >> mb = ma >>= const mb 

(Это не его фактическое определение в Monad например, для [], но это не имеет значения.)

В случае списка для каждого элемент в [1,2,3], вы получаете [1], а общий результат равен concat [[1],[1],[1]], то есть [1,1,1].

Вот пример для [] в GHC.Base:

m >>= k    = foldr ((++) . k) [] m 
m >> k    = foldr ((++) . (\ _ -> k)) [] m 

Мы конкатенации, здесь используя складку, одну копию с правой стороны для каждого элемента в левой стороне, игнорируя то, что элемент может быть.

+0

Я не понимаю вещь «const mb». const a -> b -> a, поэтому я ожидаю, что mb будет выводиться. то есть [1] – Tobi3

+0

Да, это правильно, вывод «mb» выводится. Он выводится три раза, потому что правая часть '>>' и '>> =' вызывается один раз для каждого элемента списка в левой части в случае списков. Таким образом, вы получаете '[[1], [1], [1]]'. –

14

Для любой монады, вы можете перевести a >> b как a >>= \_ -> b. В списке монады, оператор привязки (>>=) является concatMap с его аргументами переворачивается, так что ваш пример эквивалентен

concatMap (\_ -> [1]) [3, 2, 1] 

, которые вы можете оценить, как это.

concatMap (\_ -> [1]) [3, 2, 1] 
= concat (map (\_ -> [1]) [3, 2, 1]) -- definition of concatMap 
= concat [[1], [1], [1]]    -- apply map 
= [1, 1, 1]       -- apply concat 
4

return Напомним, что для списков \x -> [x]. Возможно, было бы понятнее, если бы я переписал ваш пример с точки зрения return

[1,2,3] >> return 1 

Давайте добавим некоторые делают нотация сахар

do [1,2,3] 
    return 1 

Вы можете увидеть сейчас? >> не вытаскивает значения из своего левого аргумента, только окружающий их контекст. В этом случае контекст представляет собой 3-элементный список, или, можно сказать, 3 разных варианта, которые все выбраны недетерминированно. Затем в каждом случае return 1.

Если вместо этого вы сделали

do x <- [1,2,3] 
    return x 

Тогда вы не выбором 1 в каждом конкретном случае, но x, который представляет собой конкретный выбор для каждой «ветви». Попытайтесь угадать, каков будет результат этого, и затем проверьте ghci, чтобы убедиться, что вы были правы. Затем отпустите его, и используйте эквациональные рассуждения, чтобы получить правильный ответ.

Смежные вопросы