У меня есть следующиеHaskell Monadic Операции на списках
[3,2,1] >> [1]
= [1,1,1]
Я не в полной мере понять, почему это происходит? Глядя на >> Я ожидал бы [3,2,1], но я вижу, что это разные по спискам.
Может ли кто-нибудь объяснить, почему?
У меня есть следующиеHaskell Monadic Операции на списках
[3,2,1] >> [1]
= [1,1,1]
Я не в полной мере понять, почему это происходит? Глядя на >> Я ожидал бы [3,2,1], но я вижу, что это разные по спискам.
Может ли кто-нибудь объяснить, почему?
>>
может быть определена следующим образом:
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
Мы конкатенации, здесь используя складку, одну копию с правой стороны для каждого элемента в левой стороне, игнорируя то, что элемент может быть.
Я не понимаю вещь «const mb». const a -> b -> a, поэтому я ожидаю, что mb будет выводиться. то есть [1] – Tobi3
Да, это правильно, вывод «mb» выводится. Он выводится три раза, потому что правая часть '>>' и '>> =' вызывается один раз для каждого элемента списка в левой части в случае списков. Таким образом, вы получаете '[[1], [1], [1]]'. –
Для любой монады, вы можете перевести 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
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, чтобы убедиться, что вы были правы. Затем отпустите его, и используйте эквациональные рассуждения, чтобы получить правильный ответ.
Подумайте, что произойдет, если монада 'IO' поступила бы по аналоговому пути ...' putStr «Привет,» >> putStr «world» 'будет действием, которое печатает _only_' "world". – leftaroundabout
Это может помочь, если вы объясните, почему вы ожидаете результатов, которые вы предложили. –
@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]': выберите число, затем выберите строку и верните строку, которая неявно отбрасывает число , –