Entrada e saída e parsers com combinadores

Ações em IO com do e um parser de expressões com precedência feito de combinadores.

TLDR

Perguntar sobre esta página

ChatGPTClaudePerplexityGrokGeminiCopiar e abrirDeepSeekCopiar e abrir

Ações e valores em IO

  • getLine :: IO String é uma ação, não a string lida. putStrLn :: String -> IO () cria uma ação de impressão.
  • IO () devolve (); pode imprimir ou nem produzir interação observável, como pure ().
main :: IO ()
main = do
  nome <- getLine
  let cumprimento = "Ola, " ++ nome ++ "!"
  putStrLn cumprimento

<- corre a ação e nomeia o resultado; let nomeia um cálculo puro. As ações correm por ordem. return n cria uma ação que devolve n; não interrompe o bloco como um return imperativo. length getLine é um erro de tipo: uma ação não é o valor que produz.

Parsers como funções

newtype Parser a = P (String -> [(a,String)])

Um parser lê um prefixo e devolve o valor com o resto. Nesta lição, [] é falha e [(v,resto)] é o único sucesso; o tipo permite vários pares, mas os combinadores apresentados pressupõem determinismo.

OperaçãoComportamento
itemLê um caráter: "abc" dá [('a',"bc")]; entrada vazia falha.
pure vDevolve v sem consumir entrada.
fmap f pTransforma o valor, conservando o resto.
p >>= fUsa o valor para escolher o parser seguinte, corrido no resto.
p +++ qSe p falhar, tenta q na entrada original; prefere o sucesso de p.
many p, many1 pZero ou mais, ou uma ou mais ocorrências.
token pIgnora espaços à volta de p.

parse nat "42x" lê 4, depois 2, e dá [(42,"x")]. nat :: Parser Int pressupõe que o valor cabe em Int; para naturais arbitrariamente grandes, muda o resultado para Integer.

Precedência, associatividade e progresso

A gramática é expr = term '+' expr | term, term = factor '*' term | factor, factor = '(' expr ')' | nat.

  • term agrupa produtos antes de expr os somar: 2+3*4 dá 14; (2+3)*4 dá 20.
  • A recursão à direita associa à direita. Com subtração em vez de adição, 8-3-1 daria 8-(3-1)=6; acumular à esquerda daria 4. Prioridade e associatividade são escolhas separadas.
  • Recursão à esquerda direta (expr = expr '+' term) chama o parser sem consumir nada e pode divergir.
  • many p exige que cada sucesso consuma entrada. many (pure 1) repete sem avançar.

Validar a entrada inteira

O sucesso de um prefixo não valida a entrada. parse expr "2+3x" deixa "x"; "2+" recua para o prefixo 2 e deixa "+". Uma aplicação que exige uma expressão inteira só aceita [(v,"")], depois de consumir espaços:

completa :: Parser a -> String -> Maybe a
completa p texto = case parse (token p) texto of
  [(valor, "")] -> Just valor
  _ -> Nothing

Aceita " 2 + 3*4 " com Just 14; rejeita "2+", "2+3x" e "(2+3". Este retrocesso é o contrato de +++ desta lição; outras bibliotecas distinguem falha antes e depois do consumo.

Gramática e consumo completo.

À tua maneira

Aparência

Modo de cor
Tema
Cor de destaque

Leitura

Fonte de leitura

Álgebra, lógica e uma ideia de cada vez.

Código

Fonte do código

Navegação

Cursor de leitura, sem edição. h, j, k, l movem; / pesquisa nesta página. v seleciona caracteres; V seleciona linhas; y copia. Tab permite destacar ou comentar. Espaço ou Enter abre blocos recolhíveis. Nos cartões, h, j, k, l mudam o foco.

CSS personalizado

Ativa uma sugestão ou guarda o teu CSS. Só muda este navegador.

Usa --page, --text e --accent para acompanhar o tema.

Seletores e recuperação

.site-header, .prose, .course-card, [data-reading-history], [data-playground] e .page-actions.

Abre a aparência com a tecla vírgula ou no rodapé. Se o CSS esconder os controlos, abre esta página sem CSS personalizado.

Pesquisar

Escreve para pesquisar em todo o site.

para escolher · Enter para abrir · Esc para fechar

Copiar fórmula

A cópia automática não está disponível. Copia o LaTeX abaixo.

Pesquisar nesta página

Enter procura · n / N repetem · Esc cancela. Ctrl / Cmd K pesquisa todo o site.

Atalhos de teclado

Clica numa tecla para a mudar. Esc cancela. Backspace desativa.

PesquisarCtrl / Cmd K

Os atalhos não interferem enquanto escreves. Tab e Enter funcionam sempre.