2013-05-29 5 views
12

Я только начал изучать хэскелл (буквально, сегодня!), И у меня есть небольшая проблема с пониманием логики понимания списков, в частности оператора <-. Небольшой пример по Learn You Some Haskell находит все кортежи, которые имеют длину меньше, чем 10:У меня возникли проблемы с пониманием толкований списков

ghci> let triangles = [ (a,b,c) | c <- [1..10], b <- [1..10], a <- [1..10] ] 

мое первоначальное понимание было то, что они были бы все приращение вместе, но после просмотра выхода я действительно не понимая увеличивающиеся метод для этих списки. Другой пример, который, кажется, принеси мне это:

ghci> let rightTriangles = [ (a,b,c) | c <- [1..10], b <- [1..c], a <- [1..b], a^2 + b^2 == c^2] 

Я был бы очень признателен небольшое пояснение по этим, спасибо за ваше терпение с моим отсутствием Haskell интеллекта.

ответ

20

Read [ как "список", | как «для ", <- как" in ", , как" и ".

Перечисления выполняются в вложенные мода. [ (a,b,c) | c <- [1..10], b <- [1..c], a <- [1..b], a^2 + b^2 == c^2] действительно

for c from 1 to 10 step 1: 
    for b from 1 to c step 1: 
     for a from 1 to b step 1: 
      if (a^2 + b^2 == c^2): 
      emit (a,b,c) 

В Haskell, хотя, выше достигается следующим переводом

[1..10] >>= (\c->    -- (a function of 'c', producing ... 
    [1..c] >>= (\b->    -- (a function of 'b', producing ... 
    [1..b] >>= (\a->    -- (a function of 'a', producing ... 
     if a^2+b^2==c^2 then [(a,b,c)] else [] 
     -- or: [(a,b,c) | a^2+b^2==c^2] 
    ))) 

так что вы действительно можете увидеть вложенную структуру здесь. (>>=) тоже ничего загадочного. Прочитайте >>= как «поданный» или «пробитый», хотя его официальное название «связывается». Она определяется (для списков), как

(xs >>= f) = concatMap f xs = concat (map f xs) 

f здесь называется (по map) при каждом элементе xs, в порядке. Он должен подготовить списки, чтобы их можно было комбинировать с concat. Поскольку пустые списки [] исключены на concat (например, concat [[1], [], [3]] == [1,3]), все элементы, которые не проходят тест, исключаются из конечного вывода.


Для полного перевода см section 3.11, List Comprehensions, Отчета Haskell 98. В общем случае понимание списка может содержать шаблон, а не только имя переменной. Понимание

[e | pat <- ls, ...] 

переводится как

ls >>= (\x -> case x of pat -> [e | ...] ; 
         _ -> []) 

где pat некоторый шаблон, и x это новая переменная. Когда происходит несоответствие шаблона, создается пустой список (вместо ошибки времени выполнения), и этот элемент x из ls пропускается.Это полезно для дополнительной фильтрации на основе шаблонов, например, например. [x | Just x <- ls, even x], где все Nothing s в ls спокойно игнорируются.

+5

Подробный и очень ясный, действительно помог мне понять материал. Спасибо! –

4

[ (a,b,c) | c <- [1..10], b <- [1..10], a <- [1..10] ] средства, для всех комбинаций (а, б, в), где в [1..10], б в [1..10], с в [1..10]

Если вы хотите (1,1,1) (2,2,2) видов, вы должны использовать zip: zip [1..10] [1..10] или для 3 списков, zip3 [1..10] [1..10] [1..10]

+2

Или вы можете включить [Parallel List Comprehensions] (http://www.haskell.org/ghc/docs/latest/html/users_guide/syntax-extns.html#parallel-list-comprehensions) и написать '[(a, b, c) | c <- [1..10] | b <- [1..10] | a <- [1..10]] '! – yatima2975

1

Я думаю о синтаксисе понимания списка как попытка Haskell получить Set-builder notation на языке. Мы используем '[', а не '{' и '< -', а не '∈'. Синтаксис синтаксиса List может даже быть generalized произвольным монадам.