Этот introduction объясняет синтаксис из списка. В принципе можно сказать, что каждый x <- list
означает дополнительный вложенный «for» -loop для генерации кортежей, и каждый предикат просто протестирован. Таким образом, выражение:
[(x,y) | x <- xs, even x, y <- ys, even 3*y-div x 2]
бы быть переведено на императивном языке, как:
for (var x : xs) {
if(even(x)) {
for(var y : ys) {
if(even(3*y-x/2)) {
yield (x,y)
}
}
}
yield
это ключевое слово, которое иногда используются с сопрограммами. Кроме того, что касается yield
, оценка выполняется лениво. Это позволяет, например, генерировать всех даже целые, как:
[x|x <-[2..],even x]
Список монады
Чтобы понять список понимания принципиально, нужно знать, что Monads есть. Каждое понимание списка может быть переведено в список monad. Например ваш пример переводится на:
do x <- xs
return
(do y <- ys
return (x,y))
который снова синтаксический сахар для:
xs >>= (\x -> (ys >>= \y -> return (x,y)))
монады важное понятие в функциональном программировании (и, вероятно, один лучше читает страницу википедии), потому что это немного сложно освоить. Иногда говорят, что монады похожи на burritos, ....
Как только вы более или менее понимаете монаду: монада - это тип-класс с оператором return
и оператором кантации >>
.Теперь return
заявления для внутренней части легко:
return x = [x]
Так что означает, что каждый раз, когда x
и y
установлены, вы будете создавать кортеж (x,y)
и вернуть его в качестве одноэлементного списка: таким образом [(x,y)]
. Теперь оператору «связывать» >>=
необходимо «приклеить» ys
и \y -> return (x,y)
вместе. Это делается путем его реализации, как:
(>>=) xs f = concat $ map f xs
Другими словами, вы делаете отображение и сцепить результат отображения.
Теперь, если взять вторую часть unsugared выражения во внимание:
ys >>= \y -> return (x,y)
Это означает, что для данного x
(мы теперь абстрагировать), мы будем карта каждого элемента в ys
к кортежу (x,y)
и верни это. Таким образом, мы сгенерируем список списков, каждый из которых будет синглетом, содержащим кортеж. Нечто подобное (если ys=[1,2]
):
[[(x,1)],[(x,2)]]
Теперь >>=
будет более того concat
его в:
\x -> [(x,1),(x,2)]
До сих пор мы отведенной x
прочь (предполагается, что это был один).Но теперь мы можем взять на себя первую часть этого выражения:
xs >>= \x -> [(x,1),(x,2)]
Если xs=[3,5]
, это означает, что мы создадим снова списки:
[[(3,1),(3,2)],[(5,1),(5,2)]]
и после CONCAT:
[(3,1),(3,2),(5,1),(5,2)]
Какие что мы ожидаем от:
[(x,y)|x<-[3,5],y<-[1,2]]
Прежде всего, список не проактивно построен, но с ленивой оценкой ... –
Не могли бы вы подробнее остановиться на этом? Я понимаю ленивую оценку на очень базовом уровне, но пока не знаю ее возможностей. – m0meni
Ну, список не полностью «сгенерирован» (фактически вообще не сгенерирован). Он просто хранит «определение», когда вас интересует первый элемент, он будет вычислять первый и строить новое выражение для оставшейся части и т. Д. Поэтому вы можете даже определить списки с бесконечной длиной. –