coldwa.st
Todos os guiasProgramaçãoWebDadosFerramentasBases de dadosHaskellConceitosCabal e buildsToolchainCompiladorDesempenhoEditor e HLS

Haskell · sintaxe · listas

As list comprehensions em Haskell, explicadas

Por ColdwastAtualizado a 14 de junho de 20266 min de leitura#haskell#lists#syntax
Código-fonte num ecrã
Código-fonte num ecrã — as list comprehensions são uma forma concisa de construir listas em código.

Uma das primeiras coisas que tornam Haskell elegante é a list comprehension: uma forma concisa de construir uma nova lista a partir de listas existentes, espelhando a notação matemática por compreensão de que talvez se lembre da escola. Este guia explica a sintaxe, os geradores múltiplos, as guardas e a relação entre as comprehensions e map e filter.

A sintaxe básica

Uma list comprehension tem a forma [ output | generator, condition ]. Leia a barra como «tal que»:

-- the squares of 1 to 10
squares = [x*x | x <- [1..10]]
-- [1,4,9,16,25,36,49,64,81,100]

Aqui x <- [1..10] é um gerador: extrai cada x da lista [1..10], e a parte antes da barra, x*x, é a expressão de saída aplicada a cada elemento.

Adicionar guardas (filtragem)

Linhas de código-fonte num ecrã escuro
Linhas de código no ecrã — uma guarda conserva apenas os elementos que satisfazem uma condição.

Uma guarda é uma condição booleana que conserva apenas os elementos que a satisfazem:

-- even numbers from 1 to 20, doubled
result = [x*2 | x <- [1..20], even x]
-- [4,8,12,16,20,24,28,32,36,40]

Pode combinar várias guardas, separadas por vírgulas; todas têm de ser verdadeiras para que um elemento seja incluído.

Geradores múltiplos

Com mais do que um gerador, a comprehension itera sobre cada combinação (como ciclos aninhados), por ordem:

-- all pairs from two small lists
pairs = [(x, y) | x <- [1,2,3], y <- ['a','b']]
-- [(1,'a'),(1,'b'),(2,'a'),(2,'b'),(3,'a'),(3,'b')]

O gerador mais à direita varia mais depressa. Também pode fazer um gerador posterior depender de um anterior — por exemplo, extraindo y de [x..10].

A sua relação com map e filter

Uma comprehension é essencialmente map e filter numa única forma legível. Estes são equivalentes:

[x*2 | x <- xs, even x]
map (*2) (filter even xs)

Use o que se ler melhor em cada caso. As comprehensions brilham quando tem vários geradores ou várias guardas; map/filter compõem-se bem em pipelines point-free. Como Haskell é preguiçoso, uma comprehension sobre uma lista infinita como [1..] só calcula os elementos que de facto consome.

FAQ

O que é um gerador numa list comprehension? A parte x <- xs: extrai cada valor de x da lista xs para alimentar a expressão de saída.

O que é uma guarda? Uma condição booleana (como even x) colocada depois de uma vírgula; só se conservam os elementos para os quais é verdadeira.

Posso usar vários geradores? Sim — a comprehension produz cada combinação, com o gerador mais à direita a variar mais depressa, como ciclos aninhados.

As comprehensions são apenas map e filter? Conceptualmente sim para os casos simples; as comprehensions são muitas vezes mais legíveis com vários geradores ou guardas, ao passo que map/filter se compõem bem em pipelines.

Para a linguagem por trás da sintaxe, veja o que é Haskell; as comprehensions são uma das funcionalidades que o tornam conciso e expressivo.

Guia independente, mantido pela comunidade. coldwa.st é um site de recursos de programação; este artigo é um texto explicativo novo e original sobre as list comprehensions em Haskell, sem afiliação com os maintainers da linguagem. O código reflete o comportamento padrão de Haskell/GHC — confirme com a documentação atual do GHC.