module RWH04DataPrettyBr where

import Types

-- |
chapterId= "fp"::String
language= "pt"::String

-- |
prevChapterNr= 3::Int
chapterNr= 4::Int
nextChapterNr= 5::Int

-- |
prevChapterUrl= "types-and-functions.html"::String
chapterUrl= "functional-programming.html"::String
nextChapterUrl= "writing-a-library-working-with-json-data.html"::String

-- |
prevChapterTitle= "Definir os tipos, racionalizando as funções"::String
chapterTitle= "Programação funcional"::String
nextChapterTitle= "Escrever uma biblioteca: trabalhar com dados JSON"::String


-- |
footnotes:: [FootNote]
footnotes =
  [FootNote 8 "id591518" 
            [Text "Infelizmente, não temos espaço para abordar esse desafio neste livro."]
  ,FootNote 9 "id594951" 
            [Text "The backslash was chosen for its visual resemblance to the Greek letter lambda, "
            ,Code "λ",Text ". Although ",Application "GHC"
            ,Text " can accept Unicode input, it correctly treats ",Code "λ"
            ,Text " as a letter, not as a synonym for ",Code "\\",Text "."]
  ]

-- |
chapterBr:: ([ParagrafStruct],IdParagrafList)
chapterBr= 
  ([Sect 1 "fp.thinking"
      "Pensando no Haskell"{-|    -}
      [P "x_V6",P "x_W6",P "x_X6"]
   ,Sect 1 "fp.framework"
      "Um framework de linha de comando simples"{-|    -}
      [P "x_VC1",P "InteractWith.hs:main",P "x_WC1",P "id588357",P "x_XC1",P "id588382",P "x_YC1",P "x_ZC1"]
   ,Sect 1 "fp.splitlines"
      "Warming up: Separação das linhas de texto portavel"{-|    -}
      [P "x_Y6",P "splitlines.ghci:lines",P "x_Z6",P "splitlines.ghci:lines.cr",P "x_a6",P "x_b6",P "x_d6",P "SplitLines.hs:splitLines.type",P "x_aC1",P "SplitLines.hs:splitLines",P "x_bC1",P "x_e6",P "splitlines.ghci:break",P "x_g6",P "x_cC1",P "x_h6",P "x_dC1",P "x_i6",P "x_k6",P "x_l6",P "splitlines.ghci:splitLines.foo",P "x_m6",P "splitlines.ghci:break.foo",P "x_n6",P "splitlines.ghci:splitLines.foobar",P "x_o6",P "splitlines.ghci:break.foobar",P "x_p6",P "splitlines.ghci:splitLines.bar",P "x_q6",P "splitlines.ghci:cons",P "x_eC1",P "x_fC1",
       Sect 2 "id589136"
        "Um programa de conversão de fim de linha"{-|-}
         [P "x_gC1",P "SplitLines.hs:fixLines",P "x_hC1",P "id589217",P "x_iC1",P "x_jC1",P "id589270"]]
   ,Sect 1 "fp.infix"
      "Funções infix"{-|    -}
      [P "x_K6",P "x_Rh",P "x_L6",P "Plus.hs:plus",P "x_M6",P "infix.ghci:plus",P "x_N6",P "infix.ghci:prefix",P "x_Q6",P "infix.ghci:infix",P "x_kC1",P "infix.ghci:isPrefixOf",P "x_lC1",P "infix.ghci:isInfixOf",P "x_R6",Note "Cuidados com anotação familiar em um idioma desconhecido" ["x_Sh","x_S6"]]
   ,Sect 1 "fp.lists"
      "Trabalhar com as listas"{-|    -}
      [P "x_r6",P "x_PL",P "x_s6",P "ch04.list.ghci:Data.List",P "x_t6",
       Sect 2 "fp.lists.basic"
        "Manipulação de listas básica"{-|-}
         [P "x_v6",P "ch04.list.ghci:length",P "x_mC1",P "ch04.list.ghci:null",P "x_w6",P "ch04.list.ghci:head",P "x_x6",P "ch04.list.ghci:tail",P "x_y6",P "ch04.list.ghci:last",P "x_z6",P "ch04.list.ghci:init",P "x_A7",P "ch04.list.ghci:head.empty",P "x_nC1"],
       Sect 2 "fp.lists.safe"
        "Trabalhar segura e saudavelmente a com funções crashy"{-|-}
         [P "x_B7",P "EfficientList.hs:myDumbExample",P "x_C7",P "x_D7",P "x_E7",P "x_F7",P "EfficientList.hs:mySmartExample"],
       Sect 2 "id590211"
        "Funções parcial e total"{-|-}
         [P "x_G7",P "x_H7",P "x_I7",P "x_J7"],
       Sect 2 "id590283"
        "Mais manipulações de listas simples"{-|-}
         [P "x_K7",P "ch04.list.ghci:append",P "x_L7",P "ch04.list.ghci:concat",P "x_M7",P "ch04.list.ghci:concat.multi",P "x_N7",P "ch04.list.ghci:reverse",P "x_O7",P "ch04.list.ghci:and.or",P "x_P7",P "ch04.list.ghci:all.any"],
       Sect 2 "id590714"
        "Trabalhar com sublistas"{-|-}
         [P "x_Q7",P "ch04.list.ghci:take.drop",P "x_R7",P "ch04.list.ghci:splitAt",P "x_S7",P "ch04.list.ghci:takeWhile.dropWhile",P "x_T7",P "x_U7",P "ch04.list.ghci:break.span"],
       Sect 2 "fp.list.search"
        "Buscando listas"{-|-}
         [P "x_V7",P "ch04.list.ghci:elem",P "x_W7",P "ch04.list.ghci:filter",P "x_X7",P "x_Y7",P "ch04.list.ghci:isPrefixOf",P "x_Z7",P "ch04.list.ghci:isInfixOf",P "x_a7",P "ch04.list.ghci:isSuffixOf"],
       Sect 2 "id591412"
        "Trabalhando com muitas listas ao mesmo tempo"{-|-}
         [P "x_b7",P "ch04.list.ghci:zip",P "x_c7",P "ch04.list.ghci:zipWith",P "x_d7"],
       Sect 2 "fp.lists.strings"
        "Funções especiais de manipulação de string"{-|-}
         [P "x_e7",P "ch04.list.ghci:unlines",P "x_f7",P "ch04.list.ghci:words.unwords"],
       Sect 2 "id591678"
        "Exercícios"{-|-}
         [QandAset [[P "x_g7",P "ch04.exercises.hs:safe"],[P "x_h7",P "ch04.exercises.hs:splitWith"],[P "x_pC1"],[P "x_qC1"]]]]
   ,Sect 1 "fp.loop"
      "Como pensar a respeito de loops"{-|    -}
      [P "x_i7",
       Sect 2 "fp.tailrecursion"
        "Recursão explícita"{-|-}
         [P "x_j7",P "intparse.c:as_int",P "x_k7",P "x_l7",P "IntParse.hs:type",P "x_m7",P "IntParse.hs:loop",P "x_n7",P "x_o7",P "x_p7",P "IntParse.hs:base",P "x_q7",P "x_r7",P "IntParse.hs:inductive",P "x_s7",Note "Single quotes in variable names" ["x_t7","x_u7"],P "x_v7",P "x_w7",P "intparse.ghci:example",P "x_x7",P "intparse.ghci:bad",P "x_y7",P "x_z7",P "x_A8",P "x_B8",Note "What's the big deal about tail recursion?" ["x_QL","x_RL","x_SL"]],
       Sect 2 "id592265"
        "Transformando cada peça de input"{-|-}
         [P "x_C8",P "map.c:square",P "x_D8",P "Map.hs:square",P "x_E8",P "x_F8",P "x_G8",P "map.c:uppercase",P "x_H8",P "Map.hs:upperCase",P "x_I8",P "x_J8",P "x_K8"],
       Sect 2 "id592470"
        "Mapeando sobre uma lista"{-|-}
         [P "x_L8",P "x_M8",P "Map.hs:map2",P "x_N8",P "ch04.map.ghci:type",P "x_O8",P "x_P8",P "x_Q8",P "Map.hs:myMap",Note "What are those wild cards doing there?" ["x_TL","x_UL","x_rC1"],P "x_R8",P "ch04.map.ghci:inuse",P "x_S8"],
       Sect 2 "fp.filter"
        "Seleção de peças de entrada"{-|-}
         [P "x_T8",P "Filter.hs:oddList",P "x_V8",P "ch04.filter.ghci:oddList",P "x_W8",P "ch04.filter.ghci:filter",P "x_X8"],
       Sect 2 "id592937"
        "Computing uma resposta sobre um conjunto"{-|-}
         [P "x_Z8",P "Sum.hs:mySum",P "x_a8",P "x_b8",P "Adler32.java:Adler32",P "x_c8",P "Adler32.hs:adler32",P "x_d8",P "x_sC1",P "x_e8",P "Adler32.hs:adler32_try2",P "x_f8",P "x_g8"],
       Sect 2 "fp.foldl"
        "A fold esquerda"{-|-}
         [P "x_cO1",P "Fold.hs:foldl",P "x_h8",P "x_i8",P "x_j8",P "Sum.hs:foldlSum",P "x_VL",P "Sum.hs:niceSum",P "x_k8",P "x_WL",P "Fold.hs:foldl.expand",P "x_l8",P "Adler32.hs:adler32_foldl",P "x_m8"],
       Sect 2 "id593448"
        "Por dobras usar folds, maps e filters?"{-|-}
         [P "x_n8",P "x_o8",P "x_p8"],
       Sect 2 "fp.foldr.filter"
        "Folding da direita"{-|-}
         [P "x_x8",P "Fold.hs:foldr",P "x_XL",P "Fold.hs:foldr.expand",P "x_YL",P "x_ZL",P "Fold.hs:foldr.sub",P "x_y8",P "Fold.hs:filter",P "x_z8",P "Fold.hs:myFilter",P "x_A9",P "x_B9",P "x_C9",P "Fold.hs:myMap",P "x_D9",P "Fold.hs:myFoldl",Tip "Understanding foldl in terms of foldr" ["x_E9","x_aL"],P "x_H9",P "x_I9",P "Fold.hs:identity",P "x_J9",P "fold.ghci:identity",P "x_K9",P "fold.ghci:append.builtin",P "x_L9",P "Fold.hs:append",P "x_M9",P "fold.ghci:append",P "x_bL",P "x_P9"],
       Sect 2 "id594142"
        "Folds esquerdos, preguiça e space leaks"{-|-}
         [P "x_Q9",P "x_tC1",P "id594184",P "x_uC1",P "x_vC1",P "thunky.ghci:sum",P "x_wC1",P "thunky.ghci:overflow",P "x_xC1",P "x_yC1",P "x_zC1",P "thunky.ghci:strict",P "x_AD1"],
       Sect 2 "fp.fold.exercises"
        "Exercícios"{-|-}
         [QandAset [[P "x_R9",P "ch04.exercises.hs:asInt_fold",P "x_S9",P "ch04.exercises.ghci:asInt_fold",P "x_T9",P "ch04.exercises.ghci:asInt_fold.errors"],[P "x_U9",P "ch04.exercises.hs:asInt_either",P "ch04.exercises.ghci:asInt_either"],[P "x_V9",P "ch04.exercises.hs:concat",P "x_W9"],[P "x_X9"],[P "x_Z9",P "ch04.exercises.hs:groupBy",P "x_a9"],[P "x_b9",ItemizedList [["x_BD1"],["x_CD1"],["x_DD1"],["x_ED1"]],P "x_FD1"]]],
       Sect 2 "id594881"
        "Leitura complementar"{-|-}
         [P "x_c9"]]
   ,Sect 1 "fp.anonymous"
      "Funções (lambda) anónimos"{-|    -}
      [P "x_d9",P "Partial.hs:isInAny",P "x_e9",P "x_f9",P "Partial.hs:isInAny2",P "x_g9",P "x_h9",P "x_i9",P "Lambda.hs:safeHead",P "x_j9",P "Lambda.hs:unsafeHead",P "x_k9",P "lambda.ghci:unsafeHead",P "x_l9",P "x_m9",P "x_n9",P "x_dL"]
   ,Sect 1 "fp.partialapp"
      "Aplicação da função parcial e currying"{-|    -}
      [P "x_o9",P "ch04.list.ghci:dropWhile",P "x_p9",P "x_q9",P "ch04.list.ghci:dropWhile.isSpace",P "x_s9",P "ch04.list.ghci:dropWhile.isSpace.use",P "x_t9",P "ch04.list.ghci:zip3",P "x_u9",P "ch04.list.ghci:zip3foo",P "x_v9",P "x_w9",P "x_x9",P "ch04.list.ghci:zip3foobar",P "x_y9",P "Partial.hs:isInAny3",P "x_z9",P "x_HD1",P "x_eL",P "id596294",P "x_fL",P "Sum.hs:nicerSum",
       Sect 2 "id596329"
        "Secções"{-|-}
         [P "x_AA",P "partial.ghci:section",P "x_BA",P "x_CA",P "partial.ghci:function",P "x_DA",P "partial.ghci:lower.letter",P "x_EA",P "partial.ghci:lower.string",P "x_ID1",P "Partial.hs:isInAny4"]]
   ,Sect 1 "fp.aspattern"
      "Padrões As"{-|    -}
      [P "x_FA",P "suffix.ghci:tails",P "x_GA",P "suffix.ghci:tails.empty",P "x_HA",P "SuffixTree.hs:suffixes",P "x_JA",P "x_KA",P "suffix.ghci:suffixes",P "x_LA",P "SuffixTree.hs:noAsPattern",P "x_MA",P "x_NA"]
   ,Sect 1 "fp.compose"
      "Reutilização de código através da composição"{-|    -}
      [P "x_OA",P "x_PA",P "SuffixTree.hs:suffixes2",P "x_QA",P "suffix.ghci:suffixes2",P "x_RA",P "SuffixTree.hs:compose",P "x_SA",P "SuffixTree.hs:suffixes3",P "x_TA",P "SuffixTree.hs:suffixes4",P "x_UA",P "SuffixTree.hs:suffixes5",P "x_VA",P "suffix.ghci:types",P "x_WA",P "x_JD1",P "suffix.ghci:dotty",P "x_KD1",P "suffix.ghci:words.type",P "x_LD1",P "suffix.ghci:capped.type",P "x_MD1",P "suffix.ghci:capfilt.type",P "x_ND1",P "x_XA",P "id597123",P "x_OD1",P "dlts.hs:dlts",P "x_YA",P "dlts.hs:step",P "x_ZA",P "x_aA",P "x_bA",P "dlts.ghci:words",P "x_cA",P "dlts.ghci:drop1",P "x_eA",P "dlts.ghci:head.drop1.words",
       Sect 2 "id597329"
        "Use a cabeça sabiamente"{-|-}
         [P "x_fA",P "x_gA",P "x_hA"]]
   ,Sect 1 "fp.readability"
      "Dicas para escrever código legível"{-|    -}
      [P "x_gL",P "x_hL",P "x_iL",P "x_jL",P "x_kL"]
   ,Sect 1 "fp.seq"
      "Space leaks e avaliação rigorosa"{-|    -}
      [P "x_PD1",Tip "Do you need to know all of this right now?" ["x_QD1"],
       Sect 2 "id597540"
        "Evitar space leaks com seq"{-|-}
         [P "x_RD1",P "Fold.hs:strict",P "x_SD1",P "thunky.ghci:seq",P "x_TD1",P "Fold.hs:step1",P "x_UD1",P "Fold.hs:step2",P "x_VD1",P "Fold.hs:step3",P "x_WD1",P "Fold.hs:step4",P "x_XD1"],
       Sect 2 "id597688"
        "Aprender a usar o seq"{-|-}
         [P "x_YD1",P "x_ZD1",P "Fold.hs:hiddenInside",P "x_aD1",P "Fold.hs:chained",P "x_bD1",P "Fold.hs:badExpression",P "x_cD1",P "x_dD1",P "x_eD1",P "Fold.hs:strictPair",P "x_fD1",P "x_gD1",P "x_hD1"]]
  ]
   
  
   
   
   
   
  ,[("x_V6"
    ,Paragraf [Text "Nossa aprendizagem precoce de Haskell possui dois aspectos distintos. A primeira é chegar a um acordo com a mudança de mentalidade da programação imperativa de funcionamento: temos de substituir a programação de nossos hábitos de outras línguas. Fazemos isso não porque as técnicas imperativos são ruins, mas porque, em uma linguagem funcional de outras técnicas de trabalho melhor. "])
    ,("x_W6"
    ,Paragraf [Text "O nosso segundo desafio é aprender a nossa maneira de contornar o Haskell bibliotecas padrão. Como em qualquer linguagem, bibliotecas de funcionar como alavanca, habilitando-nos a multiplicar a nossa solução de problemas de energia. Bibliotecas Haskell tendem a operar em um nível maior de abstração do que aqueles em muitas outras línguas. Precisaremos trabalhar um pouco difícil aprender usar a bibliotecas, mas na troca eles oferecem uma grande quantidade de poder. "])
    ,("x_X6"
    ,Paragraf [Text "Neste capítulo, vamos introduzir uma série de técnicas de programação funcionais. Nós vamos recorrer a exemplos de linguagens imperativas destacar a mudança no pensamento que vamos precisar fazer. Como o fazemos, nós vamos caminhar por alguns dos fundamentos da norma de bibliotecas Haskell. Nós também intermitentemente cobrir algumas línguas mais recursos no caminho. "])
    ,("x_VC1"
    ,Paragraf [Text "Na maioria deste capítulo, que incidirá nos com o código que tem qualquer interacção com o mundo exterior. Manter o foco no código prático, vamos começar por desenvolver uma passagem entre o nosso código “",Quote [QText "puro"],Text "” eo mundo lá fora. O nosso quadro simplesmente lê o conteúdo de um arquivo, aplicar uma função para o arquivo e escreve o resultado para outro arquivo. "])
    ,("InteractWith.hs:main"
    ,Listing 
      [LComment ["-- arquivo: ca04/InteraçãoCom.hs"
                ,"-- Salvar esta em um arquivo de fonte, por exemplo InteraçãoCom.hs"]
      ,LNewline,LText ["import System.Environment(getArgs)"
             ,""
             ,"interaçãoCom função nomeArquivoInput nomeArquivoOutput = do"
             ,"  input &lt;-readFile nomeArquivoInput"
             ,"  writeFile nomeArquivoOutput (função input)"
             ,""
             ,"main = mainCom funçãoMea"
             ,"  where mainCom função = do"
             ,"          entradas &lt;-getArgs"
             ,"          case entradas of"
             ,"            [input,output]-&gt; interaçãoCom função input output"
             ,"            _-&gt; putStrLn \"erro: exactamente dois argumentos necessários\""
             ,""
             ,"        "],LComment ["-- substitua \"id\" com o nome da nossa função inferior"]
      ,LNewline,LText ["        funçãoMea = id"]])
    ,("x_WC1"
    ,Paragraf [Text "Esta é a todos nós necessitamos de escrever simples, mas completa, de arquivo de programas de processamento. Esse é um programa completos. Nós podemos compilá-lo para um executável chamado ",FileName "InteraçãoCom",Text "como se segue. "])
    ,("id588357"
    ,Screen [
             ScSystemPrompt,ScUserInput ["ghc --make InteraçãoCom"],
             ScMachineResponse ["[1 of 1] Compiling Main             ( InteraçãoCom.hs, InteraçãoCom.o )"
             ,"Linking InteraçãoCom ..."]])
    ,("x_XC1"
    ,Paragraf [Text "Se executar este programa desde o reservatório ou comandos, que aceita duas nomes de arquivos: o nome da arquivo de ler, o nome e de um arquivo para escrever. "])
    ,("id588382"
    ,Screen [
             ScSystemPrompt,ScUserInput ["./InteraçãoCom"],
             ScMachineResponse ["erro: exactamente dois argumentos necessários"],
             ScSystemPrompt,ScUserInput ["./InteraçãoCom oláIn.txt oláOut.txt"],
             ScSystemPrompt,ScUserInput ["cat oláIn.txt"],
             ScMachineResponse ["Olá mundo"],
             ScSystemPrompt,ScUserInput ["cat oláOut.txt"],
             ScMachineResponse ["Olá mundo"]])
    ,("x_YC1"
    ,Paragraf [Text "Algumas das notação no nosso arquivo fonte é nova. O que introduz uma palavra-chave bloco de ações que podem provocar efeitos no mundo real, tais como a leitura ou a escrita de um arquivo. O operador ",Code "&lt;-",Text "é o equivalente de uma atribuição dentro um bloco ",Literal "do",Text ". Esta é a explicação bastante começar nós começou. Falaremos em mais detalhe muito sobre esses detalhes do notação e de I/O em geral, em ",XRef "io.html" [XText "Capítulo&nbsp;7, ",XCursive "I/O"],Text ". "])
    ,("x_ZC1"
    ,Paragraf [Text "Quando se deseja testar uma função que não pode falar com o mundo lá fora, que simplesmente substitui o nome ",Function "id",Text "ino código acima com o nome da função que queremos testar. Qualquer que seja nossa função faz, ele precisa ter o tipo de ",Type "String-&gt;String",Text ": em outras palavras, ela deve aceitar uma string e retornam uma string. "])
    ,("x_Y6"
    ,Paragraf [Text "Haskell provê uma função built-in de ",Function "lines",Text ", que deixa nós dividir uma string de texto em linha de limites. Ele retorna um lista das cadeias de caracteres com terminação de linha omitida. "])
    ,("splitlines.ghci:lines"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":t lines"],
             ScMachineResponse ["lines :: String -&gt; [String]"],
             ScGHCiPrompt,ScUserInput ["lines \"linha 1\\nlinha 2\""],
             ScMachineResponse ["[\"linha 1\",\"linha 2\"]"],
             ScGHCiPrompt,ScUserInput ["lines \"foo\\n\\nbar\\n\""],
             ScMachineResponse ["[\"foo\",\"\",\"bar\"]"]])
    ,("x_Z6"
    ,Paragraf [Text "Embora de ",Function "lines",Text "parece úteis, se baseia em nós ler um arquivo de em “",Quote [QText "modo texto"],Text "” para o trabalho. Modo texto é uma característica comum a muitas linguagens: proporciona um comportamento especial quando lêem e escrevem arquivos no Windows. Quando se lê um arquivo em modo de texto, o arquivo de biblioteca I/O traduz a fim de linha de seqüência ",Code "\"\\r\\n\"",Text "(retorno do carro seguido por nova linha) à ",Code "\"\\n\"",Text "(nova linha sozinho), e faz o inverso quando Escrever um arquivo. Em semelhante sistemas do Unix, o modo de texto não exerce qualquer translação. Como resultado desta diferença, se ler um arquivo de uma plataforma que estava escrito em outro o final de linha devem se tornar uma bagunça. (Ambos ",Function "readFile",Text "e ",Function "writeFile",Text "operar em modo texto). "])
    ,("splitlines.ghci:lines.cr"
    ,Screen [
             ScGHCiPrompt,ScUserInput ["lines \"a\\r\\nb\""],
             ScMachineResponse ["[\"a\\r\",\"b\"]"]])
    ,("x_a6"
    ,Paragraf [Text "A função ",Function "lines",Text "só divide em caracteres de nova linha, deixando retorna carro balançando nas extremidades das linhas de. Se ler um arquivo de texto gerou-Windows em um sistema Linux ou caixa Unix nós vamos arrastando carro retorna no final da cada uma delas. "])
    ,("x_b6"
    ,Paragraf [Text "Nós confortavelmente usado o suporte “",Quote [QText "universal newline"],Text "” do Python apoio a anos: trata isso de forma transparente Unix e Windows linha que termina as convenções para nós. Gostaríamos de oferecer algo similar em Haskell. "])
    ,("x_d6"
    ,Paragraf [Text "Uma vez que estamos ainda cedo em nossa carreira de leitura de código Haskell, vamos discutir nossa aplicação em Haskell bastante detalhe alguns. "])
    ,("SplitLines.hs:splitLines.type"
    ,Listing [LComment       ["-- arquivo: ca04/LinhasSeparadas.hs"]
             ,LNewline,LText ["linhasSeparadas:: String-&gt; [String]"]])
    ,("x_aC1"
    ,Paragraf [Text "A assinatura do tipo de nossa função indica que aceita uma única corda, o conteúdo de um arquivo com alguma linha que termina convenção desconhecido. Ele retorna a lista de seqüências de caracteres, que representa cada linha do processo. "])
    ,("SplitLines.hs:splitLines"
    ,Listing 
      [LComment       ["-- arquivo: ca04/LinhasSeparadas.hs"]
      ,LNewline,LText ["linhasSeparadas [] = []"
                      ,"linhasSeparadas letras ="
                      ,"    let (prefixo,sufixo) = break éSeparadorDeLinhas letras"
                      ,"    in prefixo : case sufixo of "
                      ,"        ('\\r':'\\n':resto)-&gt; linhasSeparadas resto"
                      ,"        ('\\r':resto)-&gt; linhasSeparadas resto"
                      ,"        ('\\n':resto)-&gt; linhasSeparadas resto"
                      ,"        _-&gt; []"
                      ,""
                      ,"éSeparadorDeLinhas letra = "
                      ,"    letra == '\\r' || letra == '\\n'"]])
    ,("x_bC1"
    ,Paragraf [Text "Antes de nos aprofundarmos em detalhes, como primeira notícia que se organizaram nosso Código. Nós apresentamos as partes importantes de código em primeiro lugar, mantendo a definição de ",Function "éSeparadorDeLinhas",Text "depois. Porque demos a função auxiliar um nome readable, que podemos adivinhar o que ele faz ainda antes temos lido, que facilita um “",Quote [QText "fluxo"],Text "” suave de lendo de código. "])
    ,("x_e6"
    ,Paragraf [Text "O Prelude define uma função chamada ",Function "break",Text "que podemos usar para particionar um de lista em duas partes. É preciso uma função que seu primeiro parâmetro. Essa função deverá examinar elementos de lista, e retorna uma ",Type "Bool",Text "indicar se deseja interromper a lista nesse momento. A função ",Function "break",Text "retorna um par, que consiste no sublista consumidos antes do predicado retornado ",Code "True",Text "(o ",Emphasis "prefixo",Text "), eo resto da lista (o ",Emphasis "sufixo",Text "). "])
    ,("splitlines.ghci:break"
    ,Screen [
             ScGHCiPrompt,ScUserInput ["break odd [2,4,5,6,8]"],
             ScMachineResponse ["([2,4],[5,6,8])"],
             ScGHCiPrompt,ScUserInput [":m +Data.Char"],
             ScGHCiPrompt,ScUserInput ["break isUpper \"éMaiuscula\""],
             ScMachineResponse ["(\"é\",\"Maiuscula\")"]])
    ,("x_g6"
    ,Paragraf [Text "Uma vez que só precisa corresponder a um único transporte de retorno ou nova linha de cada vez, analisar um elemento da lista ao mesmo tempo é bom o suficiente para as necessidades. "])
    ,("x_cC1"
    ,Paragraf [Text "A equação primeira de ",Function "linhasSeparadas",Text "indica que, se coincidir com uma seqüência vazia, não temos nenhum trabalho ainda a fazer. "])
    ,("x_h6"
    ,Paragraf [Text "Na equação do segundo, aplicar primeiro ",Function "break",Text "a nossa string de entrada. O prefixo é a substring antes de um terminador de linha, e sufixo é o restante do fio. O sufixo incluirão o terminador linha é eventualmente presentes."])
    ,("x_dC1"
    ,Paragraf [Text "A expressão “",Quote [QCode "prefixo :"],Text "” indica-nos que devemos adicionar o valor ",Varname "prefixo",Text "para a frente a lista das linhas. Em seguida, use uma expressão de ",Literal "case",Text "para inspecionar os sufixos, assim que nós podemos decidir o que fazer. O resultado da expressão ",Literal "case",Text "será utilizada como argumento segundo o construtor da lista ",Function "(:)",Text ". "])
    ,("x_i6"
    ,Paragraf [Text "O primeiro padrão corresponde a uma seqüência que começa com um regresso transporte, seguido por uma linha nova. A variável de ",Varname "resto",Text "está ligado ao restante da cadeia. Os outros padrões são parecidos, então elas devem ser fácil de acompanhar. "])
    ,("x_k6"
    ,Paragraf [Text "Uma descrição em prosa de uma função Haskell não necessariamente fáceis de seguir. Podemos obter uma melhor compreensão por parte entrando ",Command "ghci",Text ", e observar o comportamento da função em circunstâncias diferentes. "])
    ,("x_l6"
    ,Paragraf [Text "Começamos a separação por uma seqüência que não contém qualquer separadores de linhas. "])
    ,("splitlines.ghci:splitLines.foo"
    ,Screen [
             ScGHCiPrompt,ScUserInput ["linhasSeparadas \"foo\""],
             ScMachineResponse ["[\"foo\"]"]])
    ,("x_m6"
    ,Paragraf [Text "Aqui a nossa aplicação da ",Function "break",Text "nunca encontra um terminador de linha, assim que o sufixo retorna vazio. "])
    ,("splitlines.ghci:break.foo"
    ,Screen [
             ScGHCiPrompt,ScUserInput ["break éSeparadorDeLinhas \"foo\""],
             ScMachineResponse ["(\"foo\",\"\")"]])
    ,("x_n6"
    ,Paragraf [Text "A expressão ",Literal "case",Text "em ",Function "linhasSeparadas",Text "como tal devem ser combinados no quarto ramo e estamos acabados. E quanto um caso um pouco mais interessante? "])
    ,("splitlines.ghci:splitLines.foobar"
    ,Screen [
             ScGHCiPrompt,ScUserInput ["linhasSeparadas \"foo\\r\\nbar\""],
             ScMachineResponse ["[\"foo\",\"bar\"]"]])
    ,("x_o6"
    ,Paragraf [Text "Nossa primeira aplicação de ",Function "break",Text "nos oferece um sufixo não vazio. "])
    ,("splitlines.ghci:break.foobar"
    ,Screen [
             ScGHCiPrompt,ScUserInput ["break éSeparadorDeLinhas \"foo\\r\\nbar\""],
             ScMachineResponse ["(\"foo\",\"\\r\\nbar\")"]])
    ,("x_p6"
    ,Paragraf [Text "Devido o sufixo começa com um regresso transporte, seguido de uma nova linha, que correspondem a primeira sucursal de a expressão ",Literal "case",Text ". Isto dá-nos ",Varname "prefixo",Text "ligado a ",Code "\"foo\"",Text ", e ",Varname "sufixo",Text "ligado a ",Code "\"bar\"",Text ". Nós aplicar ",Function "linhasSeparadas",Text "recursivamente, desta vez no ",Code "\"bar\"",Text "sozinho. "])
    ,("splitlines.ghci:splitLines.bar"
    ,Screen [
             ScGHCiPrompt,ScUserInput ["linhasSeparadas \"bar\""],
             ScMachineResponse ["[\"bar\"]"]])
    ,("x_q6"
    ,Paragraf [Text "O resultado é que vamos construir a lista cuja cabeça é ",Code "\"foo\"",Text "e cuja cauda é ",Code "[\"bar\"]",Text ". "])
    ,("splitlines.ghci:cons"
    ,Screen [
             ScGHCiPrompt,ScUserInput ["\"foo\" : [\"bar\"]"],
             ScMachineResponse ["[\"foo\",\"bar\"]"]])
    ,("x_eC1"
    ,Paragraf [Text "Este tipo de experimentos com ",Command "ghci",Text "Este tipo de experimentos com ",Command "ghci",Text ", por isso tendem a gravação funciona mais pequenas. Esta pode ainda ajudar a legibilidade do código. "])
    ,("x_fC1"
    ,Paragraf [Text "Este estilo de criar e de reutilização de partes pequenas, poderoso do código é uma parte fundamental da programação funcional. "])
    ,("x_gC1"
    ,Paragraf [Text "Deixe de ligar a nossa função ",Function "linhasSeparadas",Text "em âmbito pouco que escreveu anteriormente. Faça um cópia do arquivo de fonte ",FileName "InteraçãoCom.hs",Text "; vamos chamar o arquivo novo ",FileName "LinhasAdaptadas.hs",Text ". Adicione a função ",Function "linhasSeparadas",Text "para o novo arquivo de origem. Desde a nossa função precisa elaborar um único ",Type "String",Text ", temos que costurar a lista de linhas de volta. O Prelude fornece uma função ",Function "unlines",Text "que concatena a lista das cadeias, acrescentando uma nova linha para o final de cada um. "])
    ,("SplitLines.hs:fixLines"
    ,Listing 
      [LComment       ["-- arquivo: ch04/LinhasAdaptadas.hs"]
      ,LNewline,LText ["linhasAdaptadas:: String-&gt; String"
                      ,"linhasAdaptadas input = unlines (splitLines input)"]])
    ,("x_hC1"
    ,Paragraf [Text "Se substitui a função ",Function "id",Text "com ",Function "linhasAdaptadas",Text ", podemos compilar um executável que irá converter um arquivo de texto para a linha materna nosso sistema termina. "])
    ,("id589217"
    ,Screen [
             ScSystemPrompt,ScUserInput ["ghc --make LinhasAdaptadas"],
             ScMachineResponse ["[1 of 1] Compiling Main             ( LinhasAdaptadas.hs, LinhasAdaptadas.o )"
             ,"Linking LinhasAdaptadas ..."]])
    ,("x_iC1"
    ,Paragraf [Text "Se você é em um sistema Windows, localizar e transferir um arquivo texto criado em um sistema Unix (por exemplo ",ULink "http://www.gnu.org/licenses/gpl-3.0.txt" "gpl-3.0.txt",Text "). Abrir no editor texto padrão Notepad. As linhas devem correr tudo junto, fazendo o arquivo praticamente ilegível. Process o ficheiro utilizando o ",Command "LinhasAdaptadas",Text "mando criado e abra o arquivo de saída no Bloco de notas. As terminações de linha agora deve ser fixada acima. "])
    ,("x_jC1"
    ,Paragraf [Text "Em semelhantes os sistemas Unix, o padrão pagers e editores esconder terminações de linha de Windows. Isto faz mais difícil de verificar se ",Command "LinhasAdaptadas",Text "é realmente eliminá-los. Aqui estão uns poucos comandos que deve ajudar. "])
    ,("id589270"
    ,Screen [
             ScSystemPrompt,ScUserInput ["file gpl-3.0.txt"],
             ScMachineResponse ["gpl-3.0.txt: ASCII English text"],
             ScSystemPrompt,ScUserInput ["unix2dos gpl-3.0.txt"],
             ScMachineResponse ["unix2dos: converting file gpl-3.0.txt to DOS format ..."],
             ScSystemPrompt,ScUserInput ["file gpl-3.0.txt"],
             ScMachineResponse ["gpl-3.0.txt: ASCII English text, with CRLF line terminators"]])
    ,("x_K6"
    ,Paragraf [Text "Normalmente, quando se define ou aplicar uma função em Haskell, nós escrevemos o nome da função, seguido por seus argumentos. Esta notação é chamada de ",Emphasis "prefixo",Text ", porque o nome da função vem perante seus argumentos. "])
    ,("x_Rh"
    ,Paragraf [Text "Caso uma função ou construtor necessários dois ou mais discussões, temos a opção de utilização em formulário ",Emphasis "infixo",Text ", onde colocar ",Emphasis "entre",Text "sua argumentos e segundo antes. O que nos permite usar funções como operador infixo. "])
    ,("x_L6"
    ,Paragraf [Text "Definir ou aplicar uma função de construtor ou o valor usando a notação infixo, nós coloque seu nome nos personagens backtick (também conhecido como backquotes). Aqui estão as definições infixo simples de uma função e um tipo. "])
    ,("Plus.hs:plus"
    ,Listing 
      [LComment          ["-- arquivo: ca04/Plus.hs"]
      ,LNewline,LText    ["e `plus` d = e + d"
                         ,""
                         ,"data e `Par` d = e `Par` d"
                         ,"                 deriving Show"]
      ,LNewline,LComment ["-- podemos usar o construtor prefixo ou infixo"]
      ,LNewline,LText    ["foo= Par 1 2"
                         ,"bar= True `Par` \"quux\""]])
    ,("x_M6"
    ,Paragraf [Text "Dado que a notação infixa é meramente uma conveniência sintático, não muda a função de comportamento um. "])
    ,("infix.ghci:plus"
    ,Screen [
             ScGHCiPrompt,ScUserInput ["1 `plus` 2"],
             ScMachineResponse ["3"],
             ScGHCiPrompt,ScUserInput ["plus 1 2"],
             ScMachineResponse ["3"],
             ScGHCiPrompt,ScUserInput ["True `Par` \"uma coisa\""],
             ScMachineResponse ["True `Par` \"uma coisa\""],
             ScGHCiPrompt,ScUserInput ["Par True \"uma coisa\""],
             ScMachineResponse ["True `Par` \"uma coisa\""]])
    ,("x_N6"
    ,Paragraf [Text "A notação Infix pode frequentemente ajudar legibilidade. De exemplo Prelude define uma função, ",Function "elem",Text ", que indicam se há um valor presente em um de lista. Se usarmos ",Function "elem",Text "com anotação de prefixo, é bastante fácil de ler. "])
    ,("infix.ghci:prefix"
    ,Screen [
             ScGHCiPrompt,ScUserInput ["elem 'a' \"Macumba\""],
             ScMachineResponse ["True"]])
    ,("x_Q6"
    ,Paragraf [Text "Se vamos mudar a infixo registo, o código fica até mais fácil de entender. É agora claro que estamos verificando se o valor à esquerda está presente na lista da certo. "])
    ,("infix.ghci:infix"
    ,Screen [
             ScGHCiPrompt,ScUserInput ["3 `elem` [1,2,4,8]"],
             ScMachineResponse ["False"]])
    ,("x_kC1"
    ,Paragraf [Text "Vemos uma expressiva melhora mais com algumas funções úteis da módulo ",Code "Data.List",Text ". A função ",Function "isPrefixOf",Text "diz-nos se numa lista coincide com o começo de outra. "])
    ,("infix.ghci:isPrefixOf"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":m +Data.List"],
             ScGHCiPrompt,ScUserInput ["\"foo\" `isPrefixOf` \"foobar\""],
             ScMachineResponse ["True"]])
    ,("x_lC1"
    ,Paragraf [Text "As funções ",Function "isInfixOf",Text "e ",Function "isSuffixOf",Text "corresponder qualquer lugar em um lista e em seu final, respectivamente. "])
    ,("infix.ghci:isInfixOf"
    ,Screen [
             ScGHCiPrompt,ScUserInput ["\"agulha\" `isInfixOf` \"palheiro cheio de agulhas\""],
             ScMachineResponse ["True"],
             ScGHCiPrompt,ScUserInput ["\"fim\" `isSuffixOf` \"o fim\""],
             ScMachineResponse ["True"]])
    ,("x_R6"
    ,Paragraf [Text "Não há e rápida regra rígida que determina quando você deveria usar infixo versus notação de prefixo, apesar de notação de prefixo é muito mais comuns. É a mais melhor escolher o que faz o seu código mais legível em uma determinada situação. "])
    ,("x_Sh"
    ,Paragraf [Text "A algumas outras linguagens de programação utilizar backticks mas, apesar das semelhanças visual, a fim de backticks em Haskell não lembram remotamente o seu significado em, por exemplo: Perl, Python, shell scripts ou Unix. "])
    ,("x_S6"
    ,Paragraf [Text "A única coisa legal que podemos fazer com backticks em Haskell é envolver-los ao redor do nome da função. Não pode, por exemplo usá-las para incluir a expressão complexa cujo valor é uma função. Pode ser conveniente, se pudéssemos, mas que não é como a linguagem actual. "])
    ,("x_r6"
    ,Paragraf [Text "Como o pão ea manteiga da programação funcional, listas de merecer alguma atenção. O prelúdio norma define dezenas de funções para lidar com listas. Muitos destes serão ferramentas indispensáveis, por isso é importante que eles aprendam desde cedo."])
    ,("x_PL"
    ,Paragraf [Text "Para melhor ou pior, esta secção vai ler um pouco como uma “",Quote [QText "lista suja"],Text "” de funções. Por apresentar muitas funções de modo ao mesmo tempo? Essas funções são fáceis de aprender e absolutamente ubíqua. Se não temos essa caixa de ferramentas em nossas mãos, vamos acabar perdendo tempo reinventando funções simples que já estão presentes nas bibliotecas padrão;. Então fique com a gente como nós atravessamos a lista o esforço que você vai economizar se ser enorme."])
    ,("x_s6"
    ,Paragraf [Text "O módulo ",Code "Data.List",Text " e o casa lógica “",Quote [QText "real"],Text "” de todas as funções da lista. O Prelude meramente re-exporta uma grande subconjunto das funções exportadas pela ",Code "Data.List",Text ". Diversas funções úteis no ",Code "Data.List",Text " ",Emphasis "não",Text " são re-exportados pelo prelúdio padrão. Ao andarmos funções de lista nas seções que seguem, vamos mencionar explicitamente aqueles que estão apenas em ",Code "Data.List",Text "."])
    ,("ch04.list.ghci:Data.List"
    ,Screen [ScGHCiPrompt,ScUserInput [":m +Data.List"]])
    ,("x_t6"
    ,Paragraf [Text "Como nenhuma dessas funções é complexo ou tem mais de cerca de três linhas de Haskell para escrever, vamos ser breves nas nossas descrições de cada um. De fato, uma aprendizagem útil e rápido exercício é escrever uma definição de cada função depois que você já leu sobre isso."])
    ,("x_v6"
    ,Paragraf [Text "A função ",Function "length",Text " nos informa quantos elementos estão em uma lista."])
    ,("ch04.list.ghci:length"
    ,Screen [ScGHCiPrompt,ScUserInput [":t length"],
             ScMachineResponse ["length :: [a] -&gt; Int"],ScGHCiPrompt,ScUserInput ["length []"],
             ScMachineResponse ["0"],
             ScGHCiPrompt,ScUserInput ["length [1,2,3]"],
             ScMachineResponse ["3"],
             ScGHCiPrompt,ScUserInput ["length \"strings somos listas, também\""],{-|??-}
             ScMachineResponse ["22"]])
    ,("x_mC1"
    ,Paragraf [Text "Se você precisa determinar se uma lista está vazia, use a função ",Function "null",Text "."])
    ,("ch04.list.ghci:null"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":t null"],
             ScMachineResponse ["null :: [a] -&gt; Bool"],
             ScGHCiPrompt,ScUserInput ["null []"],
             ScMachineResponse ["True"],
             ScGHCiPrompt,ScUserInput ["null \"plugh\""],
             ScMachineResponse ["False"]])
    ,("x_w6"
    ,Paragraf [Text "Para acessar o primeiro elemento de uma lista, usamos a função ",Function "head",Text "."])
    ,("ch04.list.ghci:head"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":t head"],
             ScMachineResponse ["head :: [a] -&gt; a"],
             ScGHCiPrompt,ScUserInput ["head [1,2,3]"],
             ScMachineResponse ["1"]])
    ,("x_x6"
    ,Paragraf [Text "O inverso, ",Function "tail",Text ", volta tudo, ",Emphasis "mas",Text " a cabeça de uma lista."])
    ,("ch04.list.ghci:tail"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":t tail"],
             ScMachineResponse ["tail :: [a] -&gt; [a]"],
             ScGHCiPrompt,ScUserInput ["tail \"foo\""],
             ScMachineResponse ["\"oo\""]])
    ,("x_y6"
    ,Paragraf [Text "Outra função, ",Function "last",Text ", retorna o último elemento de uma lista."])
    ,("ch04.list.ghci:last"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":t last"],
             ScMachineResponse ["last :: [a] -&gt; a"],
             ScGHCiPrompt,ScUserInput ["last \"bar\""],
             ScMachineResponse ["'r'"]])
    ,("x_z6"
    ,Paragraf [Text "O inverso da ",Function "last",Text " é ",Function "init",Text ", que retorna uma lista de todos mas o último elemento de sua entrada."])
    ,("ch04.list.ghci:init"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":t init"],
             ScMachineResponse ["init :: [a] -&gt; [a]"],
             ScGHCiPrompt,ScUserInput ["init \"bar\""],
             ScMachineResponse ["\"ba\""]])
    ,("x_A7"
    ,Paragraf [Text "Várias das funções acima se comportam mal em uma lista vazia, então tome cuidado se você não souber ou não uma lista está vazia. Como se dá sua má conduta tomar?"])
    ,("ch04.list.ghci:head.empty"
    ,Screen [
             ScGHCiPrompt,ScUserInput ["head []"],
             ScMachineResponse ["*** Exception: Prelude.head: empty list"]])
    ,("x_nC1"
    ,Paragraf [Text "Tente cada uma das funções acima, no ",Command "ghci",Text ". Quais falhar quando dada uma lista vazia?"])
    ,("x_B7"
    ,Paragraf [Text "Quando queremos usar uma função como a ",Function "head",Text ", onde sabemos que poderia explodir em nós se passar em uma lista vazia, a tentação pode inicialmente ser forte para verificar o comprimento da lista antes que chamamos de ",Function "head",Text ". Vamos construir um exemplo artificial para ilustrar o nosso ponto."])
    ,("EfficientList.hs:myDumbExample"
    ,Listing [LComment ["-- arquivo: ca04/ListaEfficiente.hs"]
             ,LNewline,LText ["meuExemploEstúpido xs = if length xs &gt; 0"
                             ,"                        then head xs"
                             ,"                        else 'Z'"]])
    ,("x_C7"
    ,Paragraf [Text "Se nós estamos vindo de uma linguagem como Perl ou Python, isso pode parecer uma forma perfeitamente natural para escrever este ensaio. Nos bastidores, as listas de Python são matrizes, matrizes e Perl são, assim, matrizes. Então, eles necessariamente saber quanto tempo eles estão, e chamando ",Code "len(foo)",Text " ou ",Code "scalar(@foo)",Text " é natural coisa perfeitamente fazer. Mas como acontece com muitas outras coisas, não é uma boa idéia cegamente transplante de tal pressuposto em Haskell."])
    ,("x_D7"
    ,Paragraf [Text "Nós já vimos a definição do tipo de dados algébrica lista muitas vezes, e sei que a lista não armazena seu próprio comprimento explicitamente. Assim, a única maneira de ",Function "length",Text " pode operar é andar toda a lista."])
    ,("x_E7"
    ,Paragraf [Text "Portanto, quando só se preocupam ou não uma lista é vazia, chamada ",Function "length",Text " não é uma boa estratégia. Ele pode, potencialmente, fazer um trabalho muito mais do que nós queremos, se a lista que estamos trabalhando é finito. Desde Haskell nos permite facilmente criar listas de infinito, uma utilização descuidada de ",Function "length",Text " pode até resultar em um loop infinito."])
    ,("x_F7"
    ,Paragraf [Text "A função mais adequada para chamar aqui ao contrário é ",Function "null",Text ", que é executado em tempo constante. Melhor ainda, usando ",Function "null",Text " torna nosso código de indicar o imóvel da lista que realmente nos importa. Aqui estão duas maneiras de se expressar melhor ",Function "meuExemploEstúpido",Text ". "])
    ,("EfficientList.hs:mySmartExample"
    ,Listing [LComment ["-- arquivo: ca04/ListaEfficiente.hs"]
             ,LNewline,LText ["meuExemploFino xs = if not (null xs)"
                             ,"                    then head xs"
                             ,"                    else 'Z'"
                             ,""
                             ,"meuOutroExemplo (x:_) = x"
                             ,"meuOutroExemplo [] = 'Z'"]])
    ,("x_G7"
    ,Paragraf [Text "Funções que só têm valores de retorno definido para um subconjunto de entradas válidas são chamadas de funções ",Emphasis "parciais",Text " (chamar ",Function "error",Text " não se qualifica como retornar um valor!). Nós chamamos funções que retornam resultados válidos sobre os seus domínios de entrada inteira funções ",Emphasis "totais",Text "."])
    ,("x_H7"
    ,Paragraf [Text "É sempre uma boa idéia para saber se uma função que você está usando é parcial ou total. Chamar uma função parcial, com uma entrada que não pode suportar é provavelmente a maior fonte de simples, os erros evitáveis em programas Haskell."])
    ,("x_I7"
    ,Paragraf [Text "Alguns programadores Haskell ir tão longe para dar nomes de funções parciais que começam com um prefixo, como ",Code "unsafe",Text ", para que eles não podem atirar no próprio pé acidentalmente."])
    ,("x_J7"
    ,Paragraf [Text "É indiscutivelmente uma deficiência do prelúdio padrão que define um bom número funções parciais “",Quote [QText "inseguros"],Text "”, como a ",Function "head",Text ", sem oferecer equivalentes totais “",Quote [QText "seguros"],Text "”."])
    ,("x_K7"
    ,Paragraf [Text "O nome Haskell para a função “",Quote [QText "append"],Text "” é ",Function "(++)",Text ". "])
    ,("ch04.list.ghci:append"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":t (++)"],
             ScMachineResponse ["(++) :: [a] -&gt; [a] -&gt; [a]"],
             ScGHCiPrompt,ScUserInput ["\"foo\" ++ \"bar\""],
             ScMachineResponse ["\"foobar\""],
             ScGHCiPrompt,ScUserInput ["[] ++ [1,2,3]"],
             ScMachineResponse ["[1,2,3]"],
             ScGHCiPrompt,ScUserInput ["[True] ++ []"],
             ScMachineResponse ["[True]"]])
    ,("x_L7"
    ,Paragraf [Text "A função ",Function "concat",Text " recebe uma lista de listas, todas do mesmo tipo, e concatena-los em uma única lista."])
    ,("ch04.list.ghci:concat"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":t concat"],
             ScMachineResponse ["concat :: [[a]] -&gt; [a]"],
             ScGHCiPrompt,ScUserInput ["concat [[1,2,3], [4,5,6]]"],
             ScMachineResponse ["[1,2,3,4,5,6]"]])
    ,("x_M7"
    ,Paragraf [Text "Ele remove um nível de aninhamento."])
    ,("ch04.list.ghci:concat.multi"
    ,Screen [
             ScGHCiPrompt,ScUserInput ["concat [[[1,2],[3]], [[4],[5],[6]]]"],
             ScMachineResponse ["[[1,2],[3],[4],[5],[6]]"],
             ScGHCiPrompt,ScUserInput ["concat (concat [[[1,2],[3]], [[4],[5],[6]]])"],
             ScMachineResponse ["[1,2,3,4,5,6]"]])
    ,("x_N7"
    ,Paragraf [Text "A função ",Function "reverse",Text " retorna os elementos de uma lista em ordem inversa."])
    ,("ch04.list.ghci:reverse"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":t reverse"],
             ScMachineResponse ["reverse :: [a] -&gt; [a]"],
             ScGHCiPrompt,ScUserInput ["reverse \"foo\""],
             ScMachineResponse ["\"oof\""]])
    ,("x_O7"
    ,Paragraf [Text "Para listas de ",Type "Bool",Text ", as funções ",Function "and",Text " e ",Function "or",Text ", generalizar seus primos de dois argumentos",Function "(&amp;&amp;)",Text " e ",Function "(||)",Text ", sobre as listas."])
    ,("ch04.list.ghci:and.or"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":t and"],
             ScMachineResponse ["and :: [Bool] -&gt; Bool"],
             ScGHCiPrompt,ScUserInput ["and [True,False,True]"],
             ScMachineResponse ["False"],
             ScGHCiPrompt,ScUserInput ["and []"],
             ScMachineResponse ["True"],
             ScGHCiPrompt,ScUserInput [":type or"],
             ScMachineResponse ["or :: [Bool] -&gt; Bool"],
             ScGHCiPrompt,ScUserInput ["or [False,False,False,True,False]"],
             ScMachineResponse ["True"],
             ScGHCiPrompt,ScUserInput ["or []"],
             ScMachineResponse ["False"]])
    ,("x_P7"
    ,Paragraf [Text "Eles têm primos mais úteis, ",Function "all",Text " e ",Function "any",Text ", que operam em listas de qualquer tipo. Cada um leva um predicado como seu primeiro argumento, ",Function "all",Text "retorna ",Code "True",Text " se o predicado for bem-sucedido em cada elemento da lista, enquanto ",Function "any",Text "retorna ",Code "True",Text " se o predicado for bem-sucedido em pelo menos um elemento da lista."])
    ,("ch04.list.ghci:all.any"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":t all"],
             ScMachineResponse ["all :: (a -&gt; Bool) -&gt; [a] -&gt; Bool"],
             ScGHCiPrompt,ScUserInput ["all odd [1,3,5]"],
             ScMachineResponse ["True"],
             ScGHCiPrompt,ScUserInput ["all odd [3,1,4,1,5,9,2,6,5]"],
             ScMachineResponse ["False"],
             ScGHCiPrompt,ScUserInput ["all odd []"],
             ScMachineResponse ["True"],
             ScGHCiPrompt,ScUserInput [":type any"],
             ScMachineResponse ["any :: (a -&gt; Bool) -&gt; [a] -&gt; Bool"],
             ScGHCiPrompt,ScUserInput ["any even [3,1,4,1,5,9,2,6,5]"],
             ScMachineResponse ["True"],
             ScGHCiPrompt,ScUserInput ["any even []"],
             ScMachineResponse ["False"]])
    ,("x_Q7"
    ,Paragraf [Text "A função ",Function "take",Text ", de que já reuniu em ",XRef "types-and-functions.html#funcstypes.calling" [XText "“aplicação de função”"],Text ", retorna uma sublista consistindo de primeiros ",Emphasis "k",Text " elementos de uma lista. Seu inverso, ",Function "drop",Text ", quedas de ",Emphasis "k",Text " elementos, desde o início da lista."])
    ,("ch04.list.ghci:take.drop"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":t take"],
             ScMachineResponse ["take :: Int -&gt; [a] -&gt; [a]"],
             ScGHCiPrompt,ScUserInput ["take 3 \"foobar\""],
             ScMachineResponse ["\"foo\""],
             ScGHCiPrompt,ScUserInput ["take 2 [1]"],
             ScMachineResponse ["[1]"],
             ScGHCiPrompt,ScUserInput [":type drop"],
             ScMachineResponse ["drop :: Int -&gt; [a] -&gt; [a]"],
             ScGHCiPrompt,ScUserInput ["drop 3 \"xyzzy\""],
             ScMachineResponse ["\"zy\""],
             ScGHCiPrompt,ScUserInput ["drop 1 []"],
             ScMachineResponse ["[]"]])
    ,("x_R7"
    ,Paragraf [Text "A função ",Function "splitAt",Text " combina as funções de ",Function "take",Text " e ",Function "drop",Text ", voltando um par da lista de entrada, dividido o índice determinado."])
    ,("ch04.list.ghci:splitAt"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":t splitAt"],
             ScMachineResponse ["splitAt :: Int -&gt; [a] -&gt; ([a], [a])"],
             ScGHCiPrompt,ScUserInput ["splitAt 3 \"foobar\""],
             ScMachineResponse ["(\"foo\",\"bar\")"]])
    ,("x_S7"
    ,Paragraf [Text "As funções ",Function "takeWhile",Text " e ",Function "dropWhile",Text "levar predicados: ",Function "takeWhile",Text " toma elementos a partir do início de uma lista tão longa quanto o predicado retornar ",Code "True",Text ", enquanto ",Function "dropWhile",Text " gotas elementos da lista, enquanto o predicado retornar ",Code "True",Text "."])
    ,("ch04.list.ghci:takeWhile.dropWhile"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":t takeWhile"],
             ScMachineResponse ["takeWhile :: (a -&gt; Bool) -&gt; [a] -&gt; [a]"],
             ScGHCiPrompt,ScUserInput ["takeWhile odd [1,3,5,6,8,9,11]"],
             ScMachineResponse ["[1,3,5]"],
             ScGHCiPrompt,ScUserInput [":type dropWhile"],
             ScMachineResponse ["dropWhile :: (a -&gt; Bool) -&gt; [a] -&gt; [a]"],
             ScGHCiPrompt,ScUserInput ["dropWhile even [2,4,6,7,9,10,12]"],
             ScMachineResponse ["[7,9,10,12]"]])
    ,("x_T7"
    ,Paragraf [Text "Assim como ",Function "splitAt",Text "“",Quote [QText "tuplas"],Text "” os resultados de ",Function "take",Text " e ",Function "drop",Text ", as funções ",Function "break",Text " (que já vimos na ",XRef "#fp.splitlines" [XText "seção chamada “Warming up: Separação das linhas de texto portavel”"],Text ") e ",Function "span",Text " até tupla os resultados de ",Function "takeWhile",Text " e ",Function "dropWhile",Text "."])
    ,("x_U7"
    ,Paragraf [Text "Cada função tem um predicado; ",Function "break",Text " consome a sua entrada enquanto o predicado falha, enquanto ",Function "span",Text " consome enquanto seu predicado êxito."])
    ,("ch04.list.ghci:break.span"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":t span"],
             ScMachineResponse ["span :: (a -&gt; Bool) -&gt; [a] -&gt; ([a], [a])"],
             ScGHCiPrompt,ScUserInput ["span even [2,4,6,7,9,10,11]"],
             ScMachineResponse ["([2,4,6],[7,9,10,11])"],
             ScGHCiPrompt,ScUserInput [":type break"],
             ScMachineResponse ["break :: (a -&gt; Bool) -&gt; [a] -&gt; ([a], [a])"],
             ScGHCiPrompt,ScUserInput ["break even [1,3,5,6,8,9,10]"],
             ScMachineResponse ["([1,3,5],[6,8,9,10])"]])
    ,("x_V7"
    ,Paragraf [Text "Como já vimos, a função ",Function "elem",Text "indica se um valor está presente em uma lista. Ele tem uma função complementar, ",Function "notElem",Text "."])
    ,("ch04.list.ghci:elem"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":t elem"],
             ScMachineResponse ["elem :: (Eq a) =&gt; a -&gt; [a] -&gt; Bool"],
             ScGHCiPrompt,ScUserInput ["2 `elem` [5,3,2,1,1]"],
             ScMachineResponse ["True"],
             ScGHCiPrompt,ScUserInput ["2 `notElem` [5,3,2,1,1]"],
             ScMachineResponse ["False"]])
    ,("x_W7"
    ,Paragraf [Text "Para uma pesquisa mais geral, ",Function "filter",Text " tem um predicado, e retorna todos os elementos da lista em que o predicado for bem-sucedido."])
    ,("ch04.list.ghci:filter"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":t filter"],
             ScMachineResponse ["filter :: (a -&gt; Bool) -&gt; [a] -&gt; [a]"],
             ScGHCiPrompt,ScUserInput ["filter odd [2,4,1,3,6,8,5,7]"],
             ScMachineResponse ["[1,3,5,7]"]])
    ,("x_X7"
    ,Paragraf [Text "Em ",Code "Data.List",Text ", três predicados, ",Function "isPrefixOf",Text ", ",Function "isInfixOf",Text " e ",Function "isSuffixOf",Text ", vamos testar a presença de sublistas dentro de uma grande lista. A maneira mais fácil de usá-los é usando a notação infixa."])
    ,("x_Y7"
    ,Paragraf [Text "A função ",Function "isPrefixOf",Text " nos diz se o seu argumento deixou coincide com o início da sua tese direita."])
    ,("ch04.list.ghci:isPrefixOf"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":m +Data.List"],
             ScGHCiPrompt,ScUserInput [":t isPrefixOf"],
             ScMachineResponse ["isPrefixOf :: (Eq a) =&gt; [a] -&gt; [a] -&gt; Bool"],
             ScGHCiPrompt,ScUserInput ["\"foo\" `isPrefixOf` \"foobar\""],
             ScMachineResponse ["True"],
             ScGHCiPrompt,ScUserInput ["[1,2] `isPrefixOf` []"],
             ScMachineResponse ["False"]])
    ,("x_Z7"
    ,Paragraf [Text "A função ",Function "isInfixOf",Text " indica se o seu argumento de esquerda é uma sublista de seu direito."])
    ,("ch04.list.ghci:isInfixOf"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":m +Data.List"],
             ScGHCiPrompt,ScUserInput ["[2,6] `isInfixOf` [3,1,4,1,5,9,2,6,5,3,5,8,9,7,9]"],
             ScMachineResponse ["True"],
             ScGHCiPrompt,ScUserInput ["\"funk\" `isInfixOf` \"sonic youth\""],
             ScMachineResponse ["False"]])
    ,("x_a7"
    ,Paragraf [Text "A operação de ",Function "isSuffixOf",Text " não deve precisar de qualquer explicação."])
    ,("ch04.list.ghci:isSuffixOf"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":m +Data.List"],
             ScGHCiPrompt,ScUserInput ["\".c\" `isSuffixOf` \"crash_o_meu.c\""],
             ScMachineResponse ["True"]])
    ,("x_b7"
    ,Paragraf [Text "A função ",Function "zip",Text "recebe duas listas e “",Quote [QText "fecha-los"],Text "” em uma única lista de pares. A lista resultante é o mesmo comprimento que o mais curto dos dois insumos."])
    ,("ch04.list.ghci:zip"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":t zip"],
             ScMachineResponse ["zip :: [a] -&gt; [b] -&gt; [(a, b)]"],
             ScGHCiPrompt,ScUserInput ["zip [12,72,93] \"zippidade\""],
             ScMachineResponse ["[(12,'z'),(72,'i'),(93,'p')]"]])
    ,("x_c7"
    ,Paragraf [Text "Mais útil é ",Function "zipWith",Text ", que pega duas listas e aplica uma função para cada par de elementos, gerando uma lista que é do mesmo comprimento que o menor dos dois."])
    ,("ch04.list.ghci:zipWith"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":t zipWith"],
             ScMachineResponse ["zipWith :: (a -&gt; b -&gt; c) -&gt; [a] -&gt; [b] -&gt; [c]"],
             ScGHCiPrompt,ScUserInput ["zipWith (+) [1,2,3] [4,5,6]"],
             ScMachineResponse ["[5,7,9]"]])
    ,("x_d7"
    ,Paragraf [Text "O sistema de tipo de Haskell torna um desafio interessante para escrever funções que recebem número variável de argumentos",FootNoteRef 8 "id591518",Text ". Portanto, se queremos zip três listas em conjunto, chamamos ",Function "zip3",Text " ou ",Function "zipWith3",Text ", e assim por diante até ",Function "zip7",Text " e ",Function "zipWith7",Text "."])
    ,("x_e7"
    ,Paragraf [Text "Nós já encontramos a função padrão ",Function "lines",Text " em ",XRef "#fp.splitlines" [XText "a seção chamada “Warming up: Separação das linhas de texto portavel”"],Text ", eo seu homólogo padrão, ",Function "unlines",Text ". Observe que ",Function "unlines",Text " sempre coloca uma nova linha no final do seu resultado."])
    ,("ch04.list.ghci:unlines"
    ,Screen [
             ScGHCiPrompt,ScUserInput ["lines \"foo\\nbar\""],
             ScMachineResponse ["[\"foo\",\"bar\"]"],
             ScGHCiPrompt,ScUserInput ["unlines [\"foo\", \"bar\"]"],
             ScMachineResponse ["\"foo\\nbar\\n\""]])
    ,("x_f7"
    ,Paragraf [Text "A função ",Function "words",Text " divide uma seqüência de entrada em qualquer espaço em branco. Sua contraparte, ",Function "unwords",Text ", usa um único espaço para participar de uma lista de palavras."])
    ,("ch04.list.ghci:words.unwords"
    ,Screen [{-| TODO: Portughese counterpart?? -}
             ScGHCiPrompt,ScUserInput ["words \"the  \\r  quick \\t  brown\\n\\n\\nfox\""],
             ScMachineResponse ["[\"the\",\"quick\",\"brown\",\"fox\"]"],
             ScGHCiPrompt,ScUserInput ["unwords [\"jumps\", \"over\", \"the\", \"lazy\", \"dog\"]"],
             ScMachineResponse ["\"jumps over the lazy dog\""]])
    ,("x_g7"
    ,Paragraf [Text "Escreva seus próprios definições “",Quote [QText "seguras"],Text "” das funções de lista parcial normal, mas certifique-se que o seu nunca falham. Como dica, você pode querer considerar usando os seguintes tipos."])
    ,("ch04.exercises.hs:safe"
    ,Listing [LComment ["-- arquivo: ca04/ch04.exercises.hs"]
             ,LNewline,LText ["safeHead:: [a]-&gt; Maybe a"
             ,"safeTail:: [a]-&gt; Maybe [a]"
             ,"safeLast:: [a]-&gt; Maybe a"
             ,"safeInit:: [a]-&gt; Maybe [a]"]])
    ,("x_h7"
    ,Paragraf [Text "Escreva uma função ",Function "splitWith",Text " que atua de forma semelhante a ",Function "words",Text ", mas leva um predicado e uma lista de qualquer tipo, e divide sua lista de entrada em cada elemento para o qual o predicado retornar ",Function "False",Text "."])
    ,("ch04.exercises.hs:splitWith"
    ,Listing [LComment ["-- arquivo: ca04/ch04.exercises.hs"]
             ,LNewline,LText ["splitWith:: (a-&gt;Bool)-&gt; [a]-&gt; [[a]]"]])
    ,("x_pC1"
    ,Paragraf [Text "Usando a estrutura de comando da ",XRef "#fp.framework" [XText "seção chamada “Um framework de linha de comando simples”"],Text ", escreva um programa que imprime a primeira palavra de cada linha de sua entrada."])
    ,("x_qC1"
    ,Paragraf [Text "Escreva um programa que transpõe o texto em um arquivo. Por exemplo, ele deve converter ",Code "\"hello\\nworld\\n\"",Text " para ",Code "\"hw\\neo\\nlr\\nll\\nod\\n\"",Text "."])
    ,("x_i7"
    ,Paragraf [Text "Diferentemente das linguagens tradicionais, Haskell não tem nem um ",Code "for",Text " loop nem ",Code "while",Text " loop. Se nós temos um monte de dados para processar, o que queremos usar no lugar? Existem várias respostas possíveis a esta pergunta."])
    ,("x_j7"
    ,Paragraf [Text "Uma maneira simples de fazer o salto a partir de uma linguagem que tem laços com uma que não é executado através de alguns exemplos, olhando para as diferenças. Aqui está uma função C que recebe uma string de dígitos decimais e os transforma em um inteiro."])
    ,("intparse.c:as_int"
    ,Listing [LText          ["int as_int(char *string){"
                             ,"    int acc; "],LComment ["/* accumulate the partial result */"]
             ,LNewline,LText ["    for(acc= 0; isdigit(*string); string++)"
                             ,"        acc= acc*10 + (*string - '0');"
                             ,"    return acc;"
                             ,"}"]])
    ,("x_k7"
    ,Paragraf [Text "Dado que Haskell não possui construções de repetição, como devemos pensar sobre o que representa um simples pedaço bastante de código como este?"])
    ,("x_l7"
    ,Paragraf [Text "Nós não temos de começar por escrever um tipo de assinatura, mas ajuda a nos lembrar que estamos trabalhando."])
    ,("IntParse.hs:type"
    ,Listing [LComment ["-- arquivo: ca04/IntParse.hs"]
             ,LNewline,LText ["import Data.Char(ord) "],LComment ["-- vamos precisar de ord em breve"]
             ,LNewline,LText [""
                             ,"asInt:: String-&gt; Int"]])
    ,("x_m7"
    ,Paragraf [Text "O código C calcula o resultado de forma incremental, uma vez que percorre a string, o código Haskell pode fazer a mesma função. No entanto, Haskell, podemos expressar o equivalente a um ciclo como um arquivo. Vamos chamar o nosso ",Function "loop",Text " só para manter as coisas agradáveis e explícita."])
    ,("IntParse.hs:loop"
    ,Listing [LComment       ["-- arquivo: ca04/IntParse.hs"]
             ,LNewline,LText ["loop:: Int-&gt; String-&gt; Int"
                             ,""
                             ,"asInt xs = loop 0 xs"]])
    ,("x_n7"
    ,Paragraf [Text "Esse primeiro parâmetro para ",Function "loop",Text " é a variável acumulador estaremos usando. Passando em zero é equivalente a inicialização do ",Varname "acc",Text " variável em C, no início do loop."])
    ,("x_o7"
    ,Paragraf [Text "Ao invés de pular em código chamas, vamos pensar sobre os dados que temos para trabalhar. Nossa ",Type "String",Text " familiar é apenas um sinônimo para ",Type "[Char]",Text ", uma lista de caracteres. A maneira mais fácil para nós para obter o direito de passagem é para pensar sobre a estrutura de uma lista: é vazia ou um único elemento seguido pelo resto da lista."])
    ,("x_p7"
    ,Paragraf [Text "Podemos expressar este pensamento estrutural directamente pelo padrão correspondente na lista de construtores do tipo. Muitas vezes é útil pensar sobre os casos fáceis primeiro: aqui, o que significa que vamos considerar o caso de lista vazia."])
    ,("IntParse.hs:base"
    ,Listing [LComment       ["-- arquivo: ca04/IntParse.hs"]
             ,LNewline,LText ["loop acc [] = acc"]])
    ,("x_q7"
    ,Paragraf [Text "Uma lista vazia não significa apenas “",Quote [QText "o String de entrada está vazia"],Text "”; é também o caso, vamos encontrar quando percorremos todo o caminho até o fim de uma lista não-vazia para fora. Então, nós não queremos “",Quote [QText "erro"],Text "” se vemos uma lista vazia. Em vez disso, devemos fazer algo sensato. Aqui, a única coisa sensata é a de terminar o ciclo, e voltar o nosso valor acumulado."])
    ,("x_r7"
    ,Paragraf [Text "O outro caso temos que considerar surge quando a lista de entrada não estiver vazia. Precisamos fazer alguma coisa com o elemento atual da lista, e algo com o resto da lista."])
    ,("IntParse.hs:inductive"
    ,Listing [LComment       ["-- arquivo: ca04/IntParse.hs"]
             ,LNewline,LText ["loop acc (x:xs) = let acc' = acc*10 + ord x"
                             ,"                  in loop acc' xs"]])
    ,("x_s7"
    ,Paragraf [Text "Calculamos um novo valor para o acumulador, e dar-lhe o nome de ",Varname "acc'",Text ". Em seguida, chamamos a função ",Function "words",Text " divide uma seqüência de entrada em qualquer espaço em branco. Sua contraparte, ",Function "unwords",Text ", usa um único espaço para participar de uma lista de palavras."])
    ,("x_t7"
    ,Paragraf [Text "Lembre-se, uma única citação é um personagem legal para usar em um nome de variável Haskell, e é pronunciado como “",Quote [QText "prime"],Text "”. Há uma expressão comum em programas Haskell envolvendo uma variável, digamos ",Varname "foo",Text " e outra variável, por exemplo ",Varname "foo'",Text ". Normalmente podemos assumir que ",Varname "foo'",Text " é de alguma forma relacionada com ",Varname "foo",Text ". É muitas vezes um novo valor para ",Varname "foo",Text ", como no nosso código acima."])
    ,("x_u7"
    ,Paragraf [Text "Às vezes, vamos ver essa expressão alargado, como ",Varname "foo''",Text ". Como manter o controle do número de aspas simples tacheada no final de um nome rapidamente se torna enfadonho, o uso de mais de dois em uma fileira, felizmente, é rara. Na verdade, mesmo uma única citação pode ser fácil de se perder, o que pode levar a confusão por parte dos leitores. Talvez seja melhor pensar no uso de aspas simples como uma convenção de codificação que você deve ser capaz de reconhecer, e menos como um que você deve realmente seguir."])
    ,("x_v7"
    ,Paragraf [Text "Cada vez que a função ",Function "loop",Text " chama a si mesmo, tem um novo valor para o acumulador, e consome um elemento da lista de entrada. Eventualmente, ele vai acertar o final da lista, em que o tempo ",Code "[]",Text " padrão irá corresponder, e as chamadas recursivas cessará."])
    ,("x_w7"
    ,Paragraf [Text "Como isso funciona bem a função? Para inteiros positivos, é perfeitamente cromulent."])
    ,("intparse.ghci:example"
    ,Screen [
             ScGHCiPrompt,ScUserInput ["asInt \"33\""],
             ScMachineResponse ["33"]])
    ,("x_x7"
    ,Paragraf [Text "Como isso funciona bem a função? Para inteiros positivos, é perfeitamente cromulent."])
    ,("intparse.ghci:bad"
    ,Screen [
             ScGHCiPrompt,ScUserInput ["asInt \"\""],
             ScMachineResponse ["0"],
             ScGHCiPrompt,ScUserInput ["asInt \"potato\""],
             ScMachineResponse ["*** Exception: Char.digitToInt: not a digit 'p'"]])
    ,("x_y7"
    ,Paragraf [Text "Vamos adiar a fixação função nossas deficiências para ",XRef "#fp.asInt.fix" [XText "Q:&nbsp;1"],Text "."])
    ,("x_z7"
    ,Paragraf [Text "Porque a última coisa que ",Function "loop",Text " faz é simplesmente chamar a si mesma, é um exemplo de uma função recursiva cauda. Há um outro idioma comum neste código, também. Pensando sobre a estrutura da lista, e manuseio e não vazio casos vazios separadamente, é um tipo de abordagem chamada de ",Emphasis "recursão estrutural",Text "."])
    ,("x_A8"
    ,Paragraf [Text "Chamamos o caso não-recursiva (quando a lista estiver vazia) o ",Emphasis "caso de base",Text "(por vezes o ",Emphasis "caso de terminação",Text "). Vamos ver as pessoas se referem ao caso em que a função chama a si mesmo como o caso recursivo (surpresa!), Ou eles podem dar um aceno para a indução matemática e chamá-lo ",Emphasis "caso indutivo",Text "."])
    ,("x_B8"
    ,Paragraf [Text "Como uma técnica útil, recursão estrutural não está confinada a lista, podemos usá-lo em outros tipos de dados algébricos, também. Teremos mais a dizer sobre isso mais tarde."])
    ,("x_QL"
    ,Paragraf [Text "Em uma linguagem imperativa, um loop é executado no espaço constante. Sem laços, nós usamos cauda funções recursivas em Haskell vez. Normalmente, uma função recursiva aloca um espaço cada vez que aplica-se, por isso sabe para onde voltar."])
    ,("x_RL"
    ,Paragraf [Text "Claramente, uma função recursiva estaria em uma enorme desvantagem em relação a um loop se memória alocada para cada aplicação recursiva: isso exigiria espaço linear em vez de espaço constante. No entanto, as implementações de linguagem funcional detectar usos de recursão de cauda, e transformar a cauda chamadas recursivas para executar no espaço constante, isso é chamado de ",Emphasis "tail call optimisation",Text ", abreviado TCO. "])
    ,("x_SL"
    ,Paragraf [Text "Poucas implementações linguagem imperativa realizar o TCO, que é por isso que usar qualquer tipo de estilo ambiciosa funcional em uma linguagem imperativa, muitas vezes leva à perda de memória e baixo desempenho."])
    ,("x_C8"
    ,Paragraf [Text "Considere uma outra função C, ",Function "quadrado",Text ", que quadrados cada elemento em um array."])
    ,("map.c:square"
    ,Listing [LText ["void quadrado(double *resultado, const double *entrada, size_t comprimento){"
                    ,"    for(size_t no= 0; no &lt; comprimento; no++)"
                    ,"        resultado[no]= entrada[no] * entrada[no];"
                    ,"}"]])
    ,("x_D8"
    ,Paragraf [Text "Este contém um tipo simples e comum de loop, que faz exatamente a mesma coisa a cada elemento da sua matriz de entrada. Como podemos escrever este circuito em Haskell?"])
    ,("Map.hs:square"
    ,Listing [LComment       ["-- arquivo: ca04/Map.hs"]
             ,LNewline,LText ["quadrado:: [Double]-&gt; [Double]"
                             ,"quadrado (x:xs) = x*x : quadrado xs"
                             ,"quadrado [] = []"]])
    ,("x_E8"
    ,Paragraf [Text "Nossa função ",Function "quadrado",Text " consiste de duas equações a correspondência de padrão. O primeiro “",Quote [QText "desconstrói"],Text "” o início de uma lista não-vazia, para obter a sua cabeça ea cauda. É praças o primeiro elemento, em seguida, coloca que na frente de uma nova lista, que é construída chamando ",Function "quadrado",Text " no restante da lista vazio. A segunda equação garante que ",Function "quadrado",Text " pára quando ela atinge o final da lista de entrada."])
    ,("x_F8"
    ,Paragraf [Text "O efeito de ",Function "quadrado",Text " é a construção de uma nova lista que é do mesmo tamanho que a sua lista de entrada, com cada elemento da lista de entrada com a sua praça substituído na lista de saída."])
    ,("x_G8"
    ,Paragraf [Text "Aqui está um outro ciclo C tal, aquele que garante que cada letra em uma string é convertida em maiúsculas."])
    ,("map.c:uppercase"
    ,Listing [LText ["#include &lt;ctype.h&gt;"
                    ,""
                    ,"char *maiuscula(const char *entrada){"
                    ,"    char *resultado= strdup(entrada);"
                    ,"    "
                    ,"    if(resultado != NULL)"
                    ,"        for(size_t no= 0; resultado[no] != '\\0'; no++)"
                    ,"            resultado[no]= toupper(resultado[no]);"
                    ,"    return resultado;"
                    ,"}"]])
    ,("x_H8"
    ,Paragraf [Text "Vamos olhar um equivalente Haskell."])
    ,("Map.hs:upperCase"
    ,Listing [LComment       ["-- arquivo: ca04/Map.hs"]
             ,LNewline,LText ["import Data.Char(toUpper)"
                             ,""
                             ,"maiuscula:: String-&gt; String"
                             ,"maiuscula (x:xs) = toUpper x : maiuscula xs"
                             ,"maiuscula [] = []"]])
    ,("x_I8"
    ,Paragraf [Text "Aqui, nós estamos importando a função ",Function "toUpper",Text " do módulo padrão ",Code "Data.Char",Text ", que contém grande quantidade de funções úteis para trabalhar com dados ",Type "Char",Text "."])
    ,("x_J8"
    ,Paragraf [Text "Nossa função ",Function "maiuscula",Text " segue um padrão semelhante à nossa função anterior ",Function "quadrado",Text ". Ele termina com uma lista vazia quando a lista de entrada está vazia, e quando a entrada não estiver vazia, ela chama ",Function "toUpper",Text " no primeiro elemento, em seguida, constrói uma nova lista de células e que o resultado de chamar-se sobre o resto da entrada lista."])
    ,("x_K8"
    ,Paragraf [Text "Estes exemplos seguem um padrão comum para escrever funções recursivas sobre listas em Haskell. O ",Emphasis "caso base",Text " lida com a situação onde a nossa entrada lista está vazia. O ",Emphasis "caso recursivo",Text " trata de uma lista não-vazia, que faz algo com a cabeça da lista, e se chama recursivamente na cauda."])
    ,("x_L8"
    ,Paragraf [Text "As funções ",Function "quadrado",Text " e ",Function "maiuscula",Text " que nós definimos produzir novas listas, que são os mesmos comprimentos de suas listas de entrada, e não apenas uma peça de trabalho por elemento. Esse é um padrão comum que prelúdio Haskell define uma função, ",Function "map",Text ", para torná-lo mais fácil. ",Function "map",Text " tem uma função, e aplica a cada elemento de uma lista, retornando uma nova lista construída a partir dos resultados dessas aplicações."])
    ,("x_M8"
    ,Paragraf [Text "Aqui estão as nossas funções ",Function "square",Text " e ",Function "maiuscula",Text " reescrito para usar ",Function "map",Text "."])
    ,("Map.hs:map2"
    ,Listing [LComment       ["-- arquivo: ca04/Map.hs"]
             ,LNewline,LText ["quadrado2 xs = map quadrado1 xs"
                             ,"    where quadrado1 x = x*x"
                             ,""
                             ,"maiuscula2 xs = map toUpper xs"]])
    ,("x_N8"
    ,Paragraf [Text "Este é o nosso primeiro olhar de perto uma função que recebe outra função como argumento. Podemos aprender muito sobre o ",Function "map",Text " simplesmente inspecionando seu tipo."])
    ,("ch04.map.ghci:type"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":t map"],
             ScMachineResponse ["map :: (a -&gt; b) -&gt; [a] -&gt; [b]"]])
    ,("x_O8"
    ,Paragraf [Text "A assinatura nos diz que ",Function "map",Text " tem dois argumentos. A primeira é uma função que assume um valor de um tipo, ",Varname "a",Text ", e retorna um valor de outro tipo, ",Varname "b",Text "."])
    ,("x_P8"
    ,Paragraf [Text "Desde ",Function "map",Text " tem uma função como argumento, nós nos referimos a ela como uma função ",Emphasis "higher-order",Text " (Apesar do nome, não há nada de misterioso sobre funções de ordem superior, é apenas um termo para funções que recebem outras funções como argumentos, ou funções de retorno.). "])
    ,("x_Q8"
    ,Paragraf [Text "Desde ",Function "map",Text " resumos o padrão comum para as nossas funções ",Function "square",Text " e ",Function "maiuscula",Text " para que possamos reutilizá-lo com menos clichê, podemos olhar para o que essas funções têm em comum e descobrir como implementá-lo nós mesmos."])
    ,("Map.hs:myMap"
    ,Listing [LComment       ["-- arquivo: ca04/Map.hs"]
             ,LNewline,LText ["meuMap:: (a-&gt;b)-&gt; [a]-&gt; [b]"
                             ,"meuMap f (x:xs) = f x : meuMap f xs"
                             ,"meuMap _ _      = []"]])
    ,("x_TL"
    ,Paragraf [Text "Se você é novo em programação funcional, as razões para os padrões de correspondência de certas maneiras, nem sempre são óbvias. Por exemplo, na definição de ",Function "meuMap",Text " acima, a primeira equação liga a função que está mapeando a variável ",Varname "f",Text ", mas o segundo usa cartões selvagens para ambos os parâmetros. O acontecendo estabele que?"])
    ,("x_UL"
    ,Paragraf [Text "Nós usamos um wild card no lugar de ",Varname "f",Text " para indicar que não estamos chamando a função ",Varname "f",Text " no lado direito da equação. E sobre a lista de parâmetros? O tipo de lista tem dois construtores. Nós já encontrados no construtor não vazia na primeira equação que define ",Function "myMap",Text ". Por eliminação, o construtor da segunda equação é necessariamente o construtor lista vazia, então não há necessidade de realizar um jogo para ver o que realmente é o seu valor."])
    ,("x_rC1"
    ,Paragraf [Text "Por uma questão de estilo, é bom para usar wild cards para o bem conhecido tipos simples, como listas e ",Type "Maybe",Text ". Para obter mais ou menos complicados tipos familiares, pode ser mais seguro e mais legível o nome construtores explicitamente."])
    ,("x_R8"
    ,Paragraf [Text "Procuramos a nossa função ",Function "meuMap",Text " para nos dar alguma garantia de que ele se comporta de forma semelhante ao ",Function "map",Text "padrão."])
    ,("ch04.map.ghci:inuse"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":m +Data.Char"],
             ScGHCiPrompt,ScUserInput ["map toLower \"SHOUTING\""],
             ScMachineResponse ["\"shouting\""],
             ScGHCiPrompt,ScUserInput ["meuMap toUpper \"whispering\""],
             ScMachineResponse ["\"WHISPERING\""],
             ScGHCiPrompt,ScUserInput ["map negate [1,2,3]"],
             ScMachineResponse ["[-1,-2,-3]"]])
    ,("x_S8"
    ,Paragraf [Text "Este padrão de manchas um idioma repetida, então abstraí-lo para que possamos reutilizar (e escrever menos!) De código, é um aspecto comum de programação Haskell. Enquanto a abstração não é exclusivo para Haskell, funções de ordem superior tornam extremamente fácil."])
    ,("x_T8"
    ,Paragraf [Text "Outra operação comum em uma seqüência de dados é um pente fino nele para os elementos que satisfaçam algum critério. Aqui está uma função que percorre uma lista de números e retorna aqueles que são estranhos. O nosso código tem um caso recursivo que é um pouco mais complexo do que nossas funções anteriores: ele só coloca um número na lista, ele retorna se o número for ímpar. Usando um guarda expressa muito bem isso."])
    ,("Filter.hs:oddList"
    ,Listing [LComment       ["-- arquivo: ca04/Filter.hs"]
             ,LNewline,LText ["listaImpar:: [Int]-&gt; [Int]"
                             ,"listaImpar (x:xs) | odd x     = x : listaImpar xs"
                             ,"                  | otherwise = listaImpar xs"
                             ,"listaImpar _                  = []"]])
    ,("x_V8"
    ,Paragraf [Text "Vamos ver isso em ação."])
    ,("ch04.filter.ghci:oddList"
    ,Screen [
             ScGHCiPrompt,ScUserInput ["listaImpar [1,1,2,3,5,8,13,21,34]"],
             ScMachineResponse ["[1,1,3,5,13,21]"]])
    ,("x_W8"
    ,Paragraf [Text "Mais uma vez, essa expressão é tão comum que o Prelude define uma função, ",Function "filter",Text ", que já introduziu. Ele elimina a necessidade de código clichê para recurse sobre a lista."])
    ,("ch04.filter.ghci:filter"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":t filter"],
             ScMachineResponse ["filter :: (a -&gt; Bool) -&gt; [a] -&gt; [a]"],
             ScGHCiPrompt,ScUserInput ["filter odd [3,1,4,1,5,9,2,6,5]"],
             ScMachineResponse ["[3,1,1,5,9,5]"]])
    ,("x_X8"
    ,Paragraf [Text "A função ",Function "filter",Text " tem um predicado e aplica a cada elemento em sua lista de entrada, retornando uma lista de apenas aqueles para os quais o predicado avaliar para ",Code "True",Text ". Nós iremos rever ",Function "filter",Text " novamente em breve, na ",XRef "#fp.foldr.filter" [XText "seção chamada “Folding da direita”"],Text "."])
    ,("x_Z8"
    ,Paragraf [Text "Outra coisa comum de se fazer com uma coleção é reduzi-lo a um único valor. Um exemplo simples disso é somar os valores de uma lista."])
    ,("Sum.hs:mySum"
    ,Listing [LComment       ["-- arquivo: ca04/Soma.hs"]
             ,LNewline,LText ["meuSoma xs = ajudante 0 xs"
                             ,"    where ajudante acc (x:xs) = ajudante (acc+x) xs"
                             ,"          ajudante acc _      = acc"]])
    ,("x_a8"
    ,Paragraf [Text "Nossa função ",Function "ajudante",Text " é cauda recursiva, e usa um parâmetro acumulador, ",Varname "acc",Text ", para segurar a soma das correntes parciais da lista. Como já vimos com ",Function "asInt",Text ", esta é uma forma “",Quote [QText "natural"],Text "” para representar um loop em uma linguagem puramente funcional."])
    ,("x_b8"
    ,Paragraf [Text "Para algo um pouco mais complicado, vamos dar uma olhada na soma de verificação Adler-32. Este é um algoritmo de soma de verificação popular, que concatena duas somas de 16 bits em um soma de verificação de 32 bits único. A primeira verificação é a soma de todos os bytes de entrada, mais um. A segunda é a soma de todos os valores intermediários da soma primeiro. Em cada caso, as somas são calculadas modulo 65521. Aqui está uma simples, a aplicação Java unoptimised. (É seguro ignorar isso se você não ler Java.)"])
    ,("Adler32.java:Adler32"
    ,Listing [LText ["public class Adler32 {"
                    ,"    private static final int base= 65521;"
                    ,""
                    ,"    public static int compute(byte[] data, int offset, int length) {"
                    ,"    int a= 1, b= 0;"
                    ,"    for (int i= offset; i &lt; offset+length; i++) {"
                    ,"        a= (a+ (data[i] &amp; 0xff)) % base;"
                    ,"        b= (a+b) % base;"
                    ,"    }"
                    ,"    return (b &lt;&lt; 16) | a;"
                    ,"    }"
                    ,"}"]])
    ,("x_c8"
    ,Paragraf [Text "Apesar de Adler-32 é uma soma simples, esse código não é muito fácil de ler por conta do bit girando envolvidos. Podemos fazer melhor com uma implementação de Haskell?"])
    ,("Adler32.hs:adler32"
    ,Listing 
      [LComment       ["-- arquivo: ca04/Adler32.hs"]
      ,LNewline,LText ["import Data.Char(ord)"
                      ,"import Data.Bits(shiftL,(.&amp;.),(.|.))"
                      ,""
                      ,"base= 65521"
                      ,""
                      ,"adler32 xs = ajudante 1 0 xs"
                      ,"    where ajudante a b (x:xs) = let a'= (a+ (ord x .&amp;. 0xff)) `mod` base"
                      ,"                                    b'= (a'+b) `mod` base"
                      ,"                                in ajudante a' b' xs"
                      ,"          ajudante a b _ = (b `shiftL` 16) .|. a"]])
    ,("x_d8"
    ,Paragraf [Text "Este código não é exatamente fácil de seguir do que o código Java, mas vamos olhar o que está acontecendo. Primeiro de tudo, nós introduzimos algumas novas funções. A função ",Function "shiftL",Text " implementa um deslocamento lógico à esquerda; "{-|TODO:explicacoes??-},Function "(.&amp;.)",Text " fornece bit a bit “",Quote [QText "e"],Text "”; e prevê ",Function "(.|.)",Text " bit a bit “",Quote [QText "ou"],Text "”."])
    ,("x_sC1"
    ,Paragraf [Text "Mais uma vez, a nossa função ",Function "ajudante",Text " é recursiva cauda. Nós viramos as duas variáveis, atualizado em cada iteração do loop em Java em parâmetros acumulador. Quando o nosso recursão termina no final da lista de entrada, calculamos nosso soma de verificação e devolvê-lo."])
    ,("x_e8"
    ,Paragraf [Text "Se dermos um passo para trás, podemos reestruturar nossas Haskell adler32 para ser mais semelhante a nossa função ",Function "meuSoma",Text " anterior. Em vez de dois parâmetros acumulador, pode-se usar um par como o acumulador."])
    ,("Adler32.hs:adler32_try2"
    ,Listing 
      [LComment       ["-- arquivo: ca04/Adler32.hs"]
      ,LNewline,LText ["adler32_2 xs = ajudante (1,0) xs"
                      ,"    where ajudante (a,b) (x:xs) ="
                      ,"              let a'= (a + (ord x .&amp;. 0xff)) `mod` base"
                      ,"                  b'= (a'+b) `mod` base"
                      ,"              in ajudante (a',b') xs"
                      ,"          ajudante (a,b) _ = (b `shiftL` 16) .|. a"]])
    ,("x_f8"
    ,Paragraf [Text "Por que nós queremos fazer essa mudança, aparentemente sem sentido estrutural? Porque, como já vimos com ",Function "map",Text " e ",Function "filter",Text ", podemos extrair o comportamento comum compartilhado por ",Function "meuSoma",Text " e ",Function "adler32_2",Text " em uma função de ordem superior. Podemos descrever esse comportamento como “",Quote [QText "fazer alguma coisa para cada elemento de uma lista, atualizando um acumulador em que estamos, e retornando o acumulador quando nós somos feitos"],Text "”."])
    ,("x_g8"
    ,Paragraf [Text "Este tipo de função é chamado de ",Emphasis "fold",Text ", porque ela “",Quote [QText "dobra"],Text "” de uma lista. Existem dois tipos de fold sobre listas, ",Function "foldl",Text " para dobrar à esquerda (no início) e ",Function "foldr",Text " para dobrar a partir da direita (o fim)."])
    ,("x_cO1"
    ,Paragraf [Text "Aqui está a definição de ",Function "foldl",Text "."])
    ,("Fold.hs:foldl"
    ,Listing [LComment       ["-- arquivo: ca04/Fold.hs"]
             ,LNewline,LText ["foldl:: (a-&gt;b-&gt;a)-&gt; a-&gt; [b]-&gt; a"
                             ,"foldl passo zero (x:xs) = foldl passo (passo zero x) xs"
                             ,"foldl _     zero []     = zero"]])
    ,("x_h8"
    ,Paragraf [Text "A função ",Function "foldl",Text " leva um função de “",Quote [QText "passo"],Text "”, um valor inicial para o acumulador e uma lista. O “",Quote [QText "passo"],Text "” leva um acumulador e um elemento da lista, e retorna um valor acumulador novo. Todo ",Function "foldl",Text " é chamar o “",Quote [QText "passo"],Text "” no acumulador atual e um elemento da lista, e passa o valor do acumulador novo para si mesmo recursivamente para consumir o restante da lista."])
    ,("x_i8"
    ,Paragraf [Text "Referimo-nos a ",Function "foldl",Text " como a “",Quote [QText "fold esquerda"],Text "” porque consome a lista da esquerda (a cabeça) para a direita."])
    ,("x_j8"
    ,Paragraf [Text "Aqui está uma regravação de ",Function "meuSoma",Text " usando ",Function "foldl",Text "."])
    ,("Sum.hs:foldlSum"
    ,Listing [LComment       ["-- arquivo: ca04/Soma.hs"]
             ,LNewline,LText ["foldlSoma xs = foldl passo 0 xs"
                             ,"    where passo acc x = acc + x"]])
    ,("x_VL"
    ,Paragraf [Text "Essa função local ",Function "passo",Text " apenas soma dois números, então vamos simplesmente usar o operador de adição ao invés, e eliminar a cláusula desnecessária ",Code "where",Text "clause. "])
    ,("Sum.hs:niceSum"
    ,Listing [LComment ["-- arquivo: ca04/Soma.hs"]
             ,LNewline,LText ["somaFina:: [Int]-&gt; Int"
                             ,"somaFina xs = foldl (+) 0 xs"]])
    ,("x_k8"
    ,Paragraf [Text "Observe como muito mais simples deste código é que o nosso ",Function "meuSoma",Text " original? Não estamos mais usando recursão explícita, porque ",Function "foldl",Text " cuida disso para nós. Nós simplificamos o nosso problema para baixo a duas coisas: que o valor inicial do acumulador deve ser (o segundo parâmetro para ",Function "foldl",Text "), e como atualizar o acumulador (a função ",Function "(+)",Text "). Como um bônus adicional, o nosso código é agora mais curto, também, o que torna mais fácil de entender."])
    ,("x_WL"
    ,Paragraf [Text "Vamos ter um olhar mais profundo que ",Function "foldl",Text " está fazendo aqui, manualmente, escrevendo cada etapa em sua avaliação, quando chamamos ",Code "somaFina [1,2,3]",Text ". "])
    ,("Fold.hs:foldl.expand"
    ,Listing [LComment       ["-- arquivo: ca04/Fold.hs"]
             ,LNewline,LText ["foldl (+) 0 (1:2:3:[])"
                             ,"          == foldl (+) (0 + 1)             (2:3:[])"
                             ,"          == foldl (+) ((0 + 1) + 2)       (3:[])"
                             ,"          == foldl (+) (((0 + 1) + 2) + 3) []"
                             ,"          ==           (((0 + 1) + 2) + 3)"]])
    ,("x_l8"
    ,Paragraf [Text "Podemos reescrever ",Function "adler32_2",Text " usando ",Function "foldl",Text " deixar-nos concentrar nos detalhes que são importantes."])
    ,("Adler32.hs:adler32_foldl"
    ,Listing [LComment       ["-- arquivo: ca04/Adler32.hs"]
             ,LNewline,LText ["adler32_foldl xs = let (a,b) = foldl passo (1,0) xs"
                             ,"                   in (b `shiftL` 16) .|. a"
                             ,"    where passo (a,b) x = let a'= a + (ord x .&amp;. 0xff)"
                             ,"                          in (a' `mod` base, (a'+b) `mod` base)"]])
    ,("x_m8"
    ,Paragraf [Text "Aqui, o nosso acumulador é um par, assim que o resultado de ",Function "foldl",Text " será, também. Puxamos o acumulador final distante quando retorna ",Function "foldl",Text " e-bit mexer-lo em uma soma de verificação “",Quote [QText "apropriada"],Text "”."])
    ,("x_n8"
    ,Paragraf [Text "Uma rápida olhada revela que ",Function "adler32_foldl",Text " não é realmente menor do que qualquer ",Function "adler32_2",Text ". Por que devemos usar uma dobra neste caso? A vantagem reside no fato de que as dobras são extremamente comuns em Haskell, e eles têm um comportamento regular e previsível."])
    ,("x_o8"
    ,Paragraf [Text "Isso significa que um leitor com um pouco de experiência terão um tempo mais fácil o entendimento a utilização de uma prega que o código que usa recursão explícita. A dobra não vai produzir nenhuma surpresa, mas o comportamento de uma função que recursivamente explicitamente não é imediatamente óbvio. recursão explícita nos obriga a ler atentamente para entender exatamente o que está acontecendo."])
    ,("x_p8"
    ,Paragraf [Text "Esta linha de raciocínio se aplica a outras funções de biblioteca de ordem superior, incluindo aqueles que já vimos, ",Function "map",Text " e ",Function "filter",Text ". Porque eles são bibliotecas de funções com comportamentos bem definidos, só precisamos saber o que eles fazem uma vez, e nós vamos ter uma vantagem quando nós precisamos de compreender qualquer código que usa-los. Estas melhorias na legibilidade também transitar para escrever código. Assim que começar a pensar com funções de ordem superior em mente, vamos produzir um código conciso mais rapidamente."])
    ,("x_x8"
    ,Paragraf [Text "A contrapartida ",Function "foldl",Text " é ",Function "foldr",Text ", a que dobra a partir da direita de uma lista."])
    ,("Fold.hs:foldr"
    ,Listing [LComment       ["-- arquivo: ca04/Fold.hs"]
             ,LNewline,LText ["foldr:: (a-&gt;b-&gt;b)-&gt; b-&gt; [a]-&gt; b"
             ,"foldr passo zero (x:xs) = passo x (foldr passo zero xs)"
             ,"foldr _     zero []     = zero"]])
    ,("x_XL"
    ,Paragraf [Text "Vamos seguir o mesmo processo de avaliação manual com ",Function "foldr (+) 0 [1,2,3]",Text " como fizemos com ",Function "somaFina",Text " na ",XRef "#fp.foldl" [XText "seção chamada “A fold esquerda”"],Text ". "])
    ,("Fold.hs:foldr.expand"
    ,Listing [LComment       ["-- arquivo: ca04/Fold.hs"]
             ,LNewline,LText ["foldr (+) 0 (1:2:3:[])"
                             ,"          == 1 +           foldr (+) 0 (2:3:[])"
                             ,"          == 1 + (2 +      foldr (+) 0 (3:[])"
                             ,"          == 1 + (2 + (3 + foldr (+) 0 []))"
                             ,"          == 1 + (2 + (3 + 0))"]])
    ,("x_YL"
    ,Paragraf [Text "A diferença entre ",Function "foldl",Text " e ",Function "foldr",Text "deve ser claro de olhar para onde os parênteses e os “",Quote [QText "lista vazia"],Text "” elementos aparecem. Com ",Function "foldl",Text ", o elemento da lista é vazia à esquerda, e todo o grupo parênteses à esquerda. Com ",Function "foldr",Text ", o valor ",Varname "zero",Text " é à direita, eo grupo de parênteses para a direita."])
    ,("x_ZL"
    ,Paragraf [Text "Há uma explicação intuitiva linda ",Function "foldr",Text " de obras como: ele substitui a lista vazia com o valor ",Varname "zero",Text ", e cada construtor na lista com uma aplicação da função de passo."])
    ,("Fold.hs:foldr.sub"
    ,Listing [LComment       ["-- arquivo: ca04/Fold.hs"]
             ,LNewline,LText ["1 : (2 : (3 : []))"
                             ,"1 + (2 + (3 + 0 ))"]])
    ,("x_y8"
    ,Paragraf [Text "À primeira vista, ",Function "foldr",Text " pode parecer menos úteis do que ",Function "foldl",Text ": o uso que é uma função que se dobra a partir da direita? Mas considere a função ",Function "filter",Text " do Prelude, que a última vez que encontrou na ",XRef "#fp.filter" [XText "seção chamada “Seleção de peças de entrada”"],Text ". Se escrevermos ",Function "filter",Text " usando recursão explícita, será algo parecido com isso."])
    ,("Fold.hs:filter"
    ,Listing [LComment       ["-- arquivo: ca04/Fold.hs"]
             ,LNewline,LText ["filter:: (a-&gt;Bool)-&gt; [a]-&gt; [a]"
                             ,"filter p []   = []"
                             ,"filter p (x:xs)"
                             ,"    | p x       = x : filter p xs"
                             ,"    | otherwise = filter p xs"]])
    ,("x_z8"
    ,Paragraf [Text "Talvez de forma surpreendente, no entanto, pode-se escrever ",Function "filter",Text " como um fold, usando ",Function "foldr",Text "."])
    ,("Fold.hs:myFilter"
    ,Listing [LComment       ["-- arquivo: ca04/Fold.hs"]
             ,LNewline,LText ["meuFilter p xs = foldr passo [] xs"
                             ,"    where passo x ys | p x       = x : ys"
                             ,"                     | otherwise = ys"]])
    ,("x_A9"
    ,Paragraf [Text "Este é o tipo de definição que poderia nos causar uma dor de cabeça, por isso vamos examiná-lo em um pouco de profundidade. Como ",Function "foldl",Text ", ",Function "foldr",Text " tem uma função e um caso-base (o que fazer quando a lista de entrada está vazia) como argumentos. Da leitura do tipo de ",Function "filter",Text ", nós sabemos que a nossa função ",Function "meuFilter",Text " deve retornar uma lista do mesmo tipo que ele consome, então o caso de base deve ser uma lista desse tipo e, a função de auxiliar ",Function "passo",Text " deve retornar uma lista."])
    ,("x_B9"
    ,Paragraf [Text "Como sabemos que ",Function "foldr ",Text " calls "{-|TODO-},Function "passo",Text "  convida um elemento da lista de entrada de cada vez, com o acumulador como seu segundo argumento, o ",Function "passo",Text " deve ser muito simples. Se o predicado retorna ",Function "True",Text ", ele empurra esse elemento para a lista acumulados, caso contrário, ele sai da lista intocada."])
    ,("x_C9"
    ,Paragraf [Text "A classe de funções que podemos expressar utilizando ",Function "foldr",Text " é chamada ",Emphasis "recursiva primitiva",Text ". Um número surpreendentemente grande de funções de manipulação de lista são recursivas primitivas. Por exemplo, aqui está a ",Function "map",Text " escrita em termos de ",Function "foldr",Text "."])
    ,("Fold.hs:myMap"
    ,Listing [LComment ["-- arquivo: ca04/Fold.hs"]
             ,LNewline,LText ["meuMap:: (a-&gt;b)-&gt; [a]-&gt; [b]"
                             ,"meuMap f xs = foldr passo [] xs"
                             ,"    where passo x ys = f x : ys"]])
    ,("x_D9"
    ,Paragraf [Text "Na verdade, podemos até escrever ",Function "foldl",Text " usando ",Function "foldr",Text "!"])
    ,("Fold.hs:myFoldl"
    ,Listing [LComment ["-- arquivo: ca04/Fold.hs"]
             ,LNewline,LText ["meuFoldl:: (a-&gt;b-&gt;a)-&gt; a-&gt; [b]-&gt; a"
             ,"meuFoldl f z xs = foldr passo id xs z"
             ,"    where passo x g a = g (f a x)"]])
    ,("x_E9"
    ,Paragraf [Text "Se você quiser definir-se um desafio contínuo, tente seguir a definição acima de ",Function "foldl",Text " usando ",Function "foldr",Text ". Esteja avisado: esta não é trivial! Você pode querer ter as seguintes ferramentas na mão: algumas pílulas de dor de cabeça e um copo de água, ",Command "ghci",Text "(para que você possa descobrir o que faz a função ",Function "id",Text "), e um lápis e papel."])
    ,("x_aL"
    ,Paragraf [Text "Você vai querer seguir o mesmo processo de avaliação manual como descrito acima para ver o que ",Function "foldl",Text " e ",Function "foldr",Text " estavam realmente fazendo. Se você ficar preso, você pode encontrar a tarefa mais fácil, depois de ler a ",XRef "#fp.partialapp" [XText "seção chamada “Aplicação da função parcial e currying”"],Text "."])
    ,("x_H9"
    ,Paragraf [Text "Voltando à nossa explicação anterior ",Function "foldr",Text " intuitiva do que faz, uma outra maneira útil de pensar sobre isso é que ele ",Emphasis "transforma",Text " sua entrada de lista. Os dois primeiros argumentos são “",Quote [QText "o que fazer com cada elemento da cauda da cabeça / da lista"],Text "”, e “",Quote [QText "o que para substituir o final da lista"],Text "”."])
    ,("x_I9"
    ,Paragraf [Text "A “",Quote [QText "identidade"],Text "” transformação com ",Function "foldr",Text "assim substitui a lista vazia com ela mesma, e aplica-se o construtor de lista para cada cabeça / cauda par:x"])
    ,("Fold.hs:identity"
    ,Listing [LComment       ["-- arquivo: ca04/Fold.hs"]
             ,LNewline,LText ["identidade:: [a]-&gt; [a]"
                             ,"identidade xs = foldr (:) [] xs"]])
    ,("x_J9"
    ,Paragraf [Text "Ela transforma uma lista em uma cópia de si mesmo."])
    ,("fold.ghci:identity"
    ,Screen [
             ScGHCiPrompt,ScUserInput ["identity [1,2,3]"],
             ScMachineResponse ["[1,2,3]"]])
    ,("x_K9"
    ,Paragraf [Text "Se ",Function "foldr",Text " substitui o fim de uma lista com algum outro valor, isto dá-nos uma outra maneira de olhar para afunção Haskell de acréscimo das listas, ",Function "(++)",Text "."])
    ,("fold.ghci:append.builtin"
    ,Screen [
             ScGHCiPrompt,ScUserInput ["[1,2,3] ++ [4,5,6]"],
             ScMachineResponse ["[1,2,3,4,5,6]"]])
    ,("x_L9"
    ,Paragraf [Text "Tudo o que temos de fazer para anexar uma lista para outra é substituir essa lista segundo para o fim da nossa primeira lista."])
    ,("Fold.hs:append"
    ,Listing [LComment ["-- arquivo: ca04/Fold.hs"]
             ,LNewline,LText ["anexado:: [a]-&gt; [a]-&gt; [a]"
                             ,"anexado xs ys = foldr (:) ys xs"]])
    ,("x_M9"
    ,Paragraf [Text "Vamos tentar fazer isso."])
    ,("fold.ghci:append"
    ,Screen [
             ScGHCiPrompt,ScUserInput ["anexado [1,2,3] [4,5,6]"],
             ScMachineResponse ["[1,2,3,4,5,6]"]])
    ,("x_bL"
    ,Paragraf [Text "Aqui, podemos substituir cada construtor lista com outro construtor da lista, mas substituir a lista vazia com a lista que deseja acrescentar sobre o fim da nossa primeira lista."])
    ,("x_P9"
    ,Paragraf [Text "Como o nosso tratamento prolongado das pregas devem indicar, a função ",Function "foldr",Text " é quase tão importante membro da nossa caixa de ferramentas de programação lista das funções mais básicas lista vimos na ",XRef "#fp.lists" [XText "seção chamada “Trabalhar com as listas”"],Text ". Pode consumir e produzir uma lista de forma incremental, o que o torna útil para a gravação de dados preguiçoso código de processamento."])
    ,("x_Q9"
    ,Paragraf [Text "Para manter o nosso simples discussão inicial, usamos ",Function "foldl",Text " durante a maior parte desta seção. Isso é conveniente para o teste, mas nunca iremos usar ",Function "foldl",Text " na prática."])
    ,("x_tC1"
    ,Paragraf [Text "A razão tem a ver com a avaliação não-estrita Haskell. Se aplicarmos ",Code "foldl (+) [1,2,3]",Text ", que avalia a expressão ",Code "(((0 + 1) + 2) + 3)",Text ". Podemos ver isso acontecer se rever a forma como a função é expandida."])
    ,("id594184"
    ,Listing [LComment       ["-- arquivo: ca04/Fold.hs"]
             ,LNewline,LText ["foldl (+) 0 (1:2:3:[])"
                             ,"          == foldl (+) (0 + 1)             (2:3:[])"
                             ,"          == foldl (+) ((0 + 1) + 2)       (3:[])"
                             ,"          == foldl (+) (((0 + 1) + 2) + 3) []"
                             ,"          ==           (((0 + 1) + 2) + 3)"]])
    ,("x_uC1"
    ,Paragraf [Text "A expressão final não será avaliada a ",Code "6",Text " até que seu valor é exigido. Antes que seja avaliada, ele deve ser armazenado como uma conversão. Não surpreendentemente, uma conversão é mais caro do que guardar um número único, e os mais complexos a expressão thunked, o espaço mais precisa. Para algo mais barata, como aritmética, thunking um expressão é computacionalmente mais caro do que avaliá-lo imediatamente. Temos, assim, acabam pagando tanto no espaço quanto no tempo."])
    ,("x_vC1"
    ,Paragraf [Text "Quando ",Application "GHC",Text " está avaliando uma expressão thunked, ele usa uma pilha interna para isso. Como uma expressão thunked poderia ser infinitamente grande, o ",Application "GHC",Text " coloca um limite fixo sobre o tamanho máximo da pilha. Graças a esse limite, podemos tentar uma expressão de grande thunked em ",Command "ghci",Text " sem precisar se preocupar que ele possa consumir toda a memória."])
    ,("thunky.ghci:sum"
    ,Screen [
             ScGHCiPrompt,ScUserInput ["foldl (+) 0 [1..1000]"],
             ScMachineResponse ["500500"]])
    ,("x_wC1"
    ,Paragraf [Text "De olhar para a expansão acima, podemos supor que este cria uma conversão que consiste em 1.000 inteiros e 999 pedidos de ",Function "(+)",Text ". Isso é um monte de memória e esforço para representar um único número! Com uma expressão maior, embora o tamanho ainda é modesta, os resultados são mais dramáticos."])
    ,("thunky.ghci:overflow"
    ,Screen [
             ScGHCiPrompt,ScUserInput ["foldl (+) 0 [1..1000000]"],
             ScMachineResponse ["*** Exception: stack overflow"]])
    ,("x_xC1"
    ,Paragraf [Text "Em expressões pequenas, ",Function "foldl",Text " irá funcionar corretamente, mas lentamente, devido à sobrecarga thunking em que incorre. Nós nos referimos a este thunking invisível como um ",Emphasis "space leak",Text "(vazamento de espaço), porque o nosso código está funcionando normalmente, mas com muito mais memória do que deveria."])
    ,("x_yC1"
    ,Paragraf [Text "Em expressões maiores, código com um vazamento de espaço simplesmente falham, como acima. Um space leak com ",Code "foldl",Text " é um obstáculo clássico para novos programadores Haskell. Felizmente, isso é fácil de evitar."])
    ,("x_zC1"
    ,Paragraf [Text "O módulo ",Code "Data.List",Text " define uma função chamada ",Function "foldl'",Text " que é semelhante ao ",Function "foldl",Text ", mas não construir thunks. A diferença de comportamento entre os dois é óbvia."])
    ,("thunky.ghci:strict"
    ,Screen [
             ScGHCiPrompt,ScUserInput ["foldl (+) 0 [1..1000000]"],
             ScMachineResponse ["*** Exception: stack overflow"],
             ScGHCiPrompt,ScUserInput [":module +Data.List"],
             ScGHCiPrompt,ScUserInput ["foldl' (+) 0 [1..1000000]"],
             ScMachineResponse ["500000500000"]])
    ,("x_AD1"
    ,Paragraf [Text "Devido ao comportamento de thunking de ",Function "foldl",Text ", é prudente evitar essa função em programas reais: mesmo que não falham completamente, será desnecessariamente ineficiente. Em vez disso, importa ",Code "Data.List",Text " e utilisa ",Function "foldl'",Text "."])
    ,("x_R9"
    ,Paragraf [Text "Use uma dobra (escolhendo a tampa adequada fará seu código muito mais simples) para reescrever e melhorar a função ",Function "asInt",Text " da ",XRef "#fp.tailrecursion" [XText "secção chamada “Recursão explícita”"],Text "."])
    ,("ch04.exercises.hs:asInt_fold"
    ,Listing [LComment       ["-- arquivo: ca04/ch04.exercises.hs"]
             ,LNewline,LText ["asInt_fold:: String-&gt; Int"]])
    ,("x_S9"
    ,Paragraf [Text "Sua função deve se comportar como se segue."])
    ,("ch04.exercises.ghci:asInt_fold"
    ,Screen [
             ScGHCiPrompt,ScUserInput ["asInt_fold \"101\""],
             ScMachineResponse ["101"],
             ScGHCiPrompt,ScUserInput ["asInt_fold \"-31337\""],
             ScMachineResponse ["-31337"],
             ScGHCiPrompt,ScUserInput ["asInt_fold \"1798\""],
             ScMachineResponse ["1798"]])
    ,("x_T9"
    ,Paragraf [Text "Estenda a sua função para tratar os seguintes tipos de condições excepcionais chamando ",Function "error",Text "."])
    ,("ch04.exercises.ghci:asInt_fold.errors"
    ,Screen [
             ScGHCiPrompt,ScUserInput ["asInt_fold \"\""],
             ScMachineResponse ["0"],
             ScGHCiPrompt,ScUserInput ["asInt_fold \"-\""],
             ScMachineResponse ["0"],
             ScGHCiPrompt,ScUserInput ["asInt_fold \"-3\""],
             ScMachineResponse ["-3"],
             ScGHCiPrompt,ScUserInput ["asInt_fold \"2.7\""],
             ScMachineResponse ["*** Exception: Char.digitToInt: not a digit '.'"],
             ScGHCiPrompt,ScUserInput ["asInt_fold \"314159265358979323846\""],
             ScMachineResponse ["564616105916946374"]])
    ,("x_U9"
    ,Paragraf [Text "A função ",Function "asInt_fold",Text " usa ",Function "error",Text ", por isso seus chamadores não pode manipular erros. Reescrevê-lo para corrigir esse problema."])
    ,("ch04.exercises.hs:asInt_either"
    ,Listing [LComment       ["-- arquivo: ca04/ch04.exercises.hs"]
             ,LNewline,LText ["type ErrorMessage = String"
                             ,"asInt_either:: String-&gt; Either ErrorMessage Int"]])
    ,("ch04.exercises.ghci:asInt_either"
    ,Screen [
             ScGHCiPrompt,ScUserInput ["asInt_either \"33\""],
             ScMachineResponse ["Right 33"],
             ScGHCiPrompt,ScUserInput ["asInt_either \"foo\""],
             ScMachineResponse ["Left \"non-digit 'o'\""]])
    ,("x_V9"
    ,Paragraf [Text "A função Prelude ",Function "concat",Text "concatena uma lista de listas em uma única lista, e digite o seguinte."])
    ,("ch04.exercises.hs:concat"
    ,Listing [LComment       ["-- arquivo: ca04/ch04.exercises.hs"]
             ,LNewline,LText ["concat:: [[a]]-&gt; [a]"]])
    ,("x_W9"
    ,Paragraf [Text "Escreva a sua própria definição de ",Function "concat",Text " usando ",Function "foldr",Text ". "])
    ,("x_X9"
    ,Paragraf [Text "Escreva a sua própria definição da função padrão ",Function "takeWhile",Text ", primeiro usando recursão explícita, então ",Function "foldr",Text "."])
    ,("x_Z9"
    ,Paragraf [Text "O módulo ",Code "Data.List",Text " define uma função, ",Function "groupBy",Text ", que tem o seguinte tipo."])
    ,("ch04.exercises.hs:groupBy"
    ,Listing [LComment       ["-- arquivo: ca04/ch04.exercises.hs"]
             ,LNewline,LText ["groupBy:: (a-&gt;a-&gt;Bool)-&gt; [a]-&gt; [[a]]"]])
    ,("x_a9"
    ,Paragraf [Text "Use ",Command "ghci",Text " para carregar o módulo ",Code "Data.List",Text " e descobrir o que ",Function "groupBy",Text " faz, em seguida, escrever sua própria implementação usando uma fold."])
    ,("x_b9"
    ,Paragraf [Text "Quantas das seguintes funções Prelude pode-se reescrever usando dobras lista?"])
    ,("x_BD1"
    ,Paragraf [Function "any"])
    ,("x_CD1"
    ,Paragraf [Function "cycle"])
    ,("x_DD1"
    ,Paragraf [Function "words"])
    ,("x_ED1"
    ,Paragraf [Function "unlines"])
    ,("x_FD1"
    ,Paragraf [Text "Para essas funções, onde você pode usar tanto ",Function "foldl'",Text " ou ",Function "foldr",Text ", que é mais adequado em cada caso?"])
    ,("x_c9"
    ,Paragraf [Text "O artigo [",Citation "bibliography.html#bib.hutton99" "Hutton99",Text "] é um excelente e profundo tutorial pregas cobertura. Ele inclui muitos exemplos de como usar técnicas simples e sistemática de cálculo para transformar funções que usam recursão explícita em folds."])
    ,("x_d9"
    ,Paragraf [Text "Em muitas das definições de funções que vimos até agora, nós escrevemos funções de auxiliar de curta duração."])
    ,("Partial.hs:isInAny"
    ,Listing [LComment       ["-- arquivo: ca04/Parcial.hs"]
             ,LNewline,LText ["isInAny needle haystack = any inSequence haystack"
             ,"    where inSequence s = needle `isInfixOf` s"]])
    ,("x_e9"
    ,Paragraf [Text "Haskell lets us write completely anonymous functions, which we can use to avoid the need to give names to our helper functions. Anonymous functions are often called “",Quote [QText "lambda"],Text "” functions, in a nod to their heritage in the lambda calculus. We introduce an anonymous function with a backslash character, ",Code "\\",Text ", pronounced ",Emphasis "lambda",FootNoteRef 9 "id594951",Text ". This is followed by the function's arguments (which can include patterns), then an arrow ",Code "-&gt;",Text "to introduce the function's body. "])
    ,("x_f9"
    ,Paragraf [Text "Lambdas are most easily illustrated by example. Here's a rewrite of ",Function "isInAny",Text "using an anonymous function. "])
    ,("Partial.hs:isInAny2"
    ,Listing [LComment       ["-- arquivo: ca04/Parcial.hs"]
             ,LNewline,LText ["isInAny2 needle haystack = any (\\s-&gt; needle `isInfixOf` s) haystack"]])
    ,("x_g9"
    ,Paragraf [Text "Nós colocaremos o lambda parênteses aqui para que Haskell pode dizer onde o corpo da função termina."])
    ,("x_h9"
    ,Paragraf [Text "Funções anónimos se comportar de forma idêntica em todos os aspectos das funções que têm nomes, mas Haskell coloca algumas restrições importantes sobre como podemos defini-los. O mais importante, enquanto nós podemos escrever uma função normal usando várias cláusulas contendo diferentes modelos e os guardas, um lambda pode ter apenas uma única cláusula na sua definição."])
    ,("x_i9"
    ,Paragraf [Text "A limitação a uma única cláusula restringe como podemos usar os padrões na definição de uma lambda. Vamos escrever uma função geralmente normal, com várias cláusulas para cobrir possibilidades diferentes padrões de correspondência."])
    ,("Lambda.hs:safeHead"
    ,Listing [LComment       ["-- arquivo: ca04/Lambda.hs"]
             ,LNewline,LText ["headSeguro (x:_) = Just x"
                             ,"headSeguro _ = Nothing"]])
    ,("x_j9"
    ,Paragraf [Text "Mas como não podemos escrever várias cláusulas para definir uma lambda, devemos estar certos de que qualquer padrão que usamos fósforo."])
    ,("Lambda.hs:unsafeHead"
    ,Listing [LComment       ["-- arquivo: ca04/Lambda.hs"]
             ,LNewline,LText ["headInseguro = \\(x:_)-&gt; x"]])
    ,("x_k9"
    ,Paragraf [Text "Esta definição de ",Function "headInseguro",Text " vai explodir em nossas faces se chamá-lo com um valor em que a correspondência de padrão falhar."])
    ,("lambda.ghci:unsafeHead"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":t headInseguro"],
             ScMachineResponse ["headInseguro :: [t] -&gt; t"],
             ScGHCiPrompt,ScUserInput ["headInseguro [1]"],
             ScMachineResponse ["1"],
             ScGHCiPrompt,ScUserInput ["headInseguro []"],
             ScMachineResponse ["*** Exception: Lambda.hs:7:13-23: Non-exhaustive patterns in lambda"
             ,""]])
    ,("x_l9"
    ,Paragraf [Text "A definição typechecks, assim ele vai compilar, então o erro irá ocorrer durante a execução. A moral desta história é que ter cuidado em como usar padrões para definir uma função anônima: certifique-se de seus padrões não pode falhar!"])
    ,("x_m9"
    ,Paragraf [Text "Outra coisa a notar sobre as funções ",Function "isInAny",Text " e ",Function "isInAny2",Text " que mostrei acima é que a primeira versão, usando uma função auxiliar que tem um nome, é um pouco mais fácil de ler que a versão que se estatela uma função anônima para o meio. A função de auxiliar nomeado não perturbar o “",Quote [QText "fluxo"],Text "” de a função na qual ele é usado, eo nome escolhido criteriosamente nos dá um pouco de informação sobre o que a função é esperado."])
    ,("x_n9"
    ,Paragraf [Text "Em contraste, quando corremos em um lambda no meio de um corpo da função, temos de trocar as marchas e ler a sua definição bastante cuidado para entender o que ele faz. Para ajudar com a legibilidade e facilidade de manutenção, então, tendemos a evitar lambdas em muitas situações onde poderíamos utilizá-los para cortar alguns personagens de uma definição de função. Muitas vezes, nós vamos usar uma função parcialmente aplicado em vez disso, resultando em um código mais claro e legível do que qualquer um lambda ou uma função explícita. Não sei o que uma função parcialmente aplicado é ainda? Leia mais!"])
    ,("x_dL"
    ,Paragraf [Text "Nós não pretendemos estas advertências para sugerir que lambdas são inúteis, mas apenas que devemos estar atentos às possíveis armadilhas quando estamos pensando em utilizá-los. Nos capítulos seguintes, veremos que são muitas vezes de valor inestimável como “",Quote [QText "cola"],Text "”."])
    ,("x_o9"
    ,Paragraf [Text "Você pode se perguntar por que a seta ",Code "-&gt;",Text " é usado para o que parece ser a dois propósitos na assinatura de um tipo de função."])
    ,("ch04.list.ghci:dropWhile"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":t dropWhile"],
             ScMachineResponse ["dropWhile :: (a -&gt; Bool) -&gt; [a] -&gt; [a]"]])
    ,("x_p9"
    ,Paragraf [Text "Parece que o ",Code "-&gt;",Text " é separar os argumentos para ",Function "dropWhile",Text " umas das outras, mas que também separa os argumentos do tipo de retorno. Mas, na verdade ",Function "-&gt;",Text " tem apenas um significado: ele denota uma função que recebe um argumento do tipo à esquerda, e retorna um valor do tipo do lado direito."])
    ,("x_q9"
    ,Paragraf [Text "A implicação aqui é muito importante: em Haskell, ",Emphasis "todas as funções de tomar apenas um argumento",Text ". Quando ",Function "dropWhile",Text " ",Emphasis "parece",Text " como uma função que recebe dois argumentos, é realmente uma função de um argumento, que retorna uma função que recebe um argumento. Aqui está uma expressão perfeitamente válida Haskell."])
    ,("ch04.list.ghci:dropWhile.isSpace"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":m +Data.Char"],
             ScGHCiPrompt,ScUserInput [":t dropWhile isSpace"],
             ScMachineResponse ["dropWhile isSpace :: [Char] -&gt; [Char]"]])
    ,("x_s9"
    ,Paragraf [Text "Bem, ",Emphasis "isso",Text " parece útil. O valor ",Code "dropWhile isSpace",Text " é uma função que retira líder espaço em branco de uma string. Como isso é útil? Como exemplo, podemos usá-lo como um argumento para uma função de ordem superior."])
    ,("ch04.list.ghci:dropWhile.isSpace.use"
    ,Screen [
             ScGHCiPrompt,ScUserInput ["map (dropWhile isSpace) [\" a\",\"f\",\"   e\"]"],
             ScMachineResponse ["[\"a\",\"f\",\"e\"]"]])
    ,("x_t9"
    ,Paragraf [Text "Toda vez que nós fornecemos um argumento para uma função, nós podemos “",Quote [QText "cortar"],Text "” um elemento fora da parte dianteira de sua assinatura tipo. Vamos tomar como exemplo ",Function "zip3",Text " para ver o que queremos dizer, esta é uma função que fecha três listas em uma lista de três tuplas."])
    ,("ch04.list.ghci:zip3"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":t zip3"],
             ScMachineResponse ["zip3 :: [a] -&gt; [b] -&gt; [c] -&gt; [(a, b, c)]"],
             ScGHCiPrompt,ScUserInput ["zip3 \"foo\" \"bar\" \"quux\""],
             ScMachineResponse ["[('f','b','q'),('o','a','u'),('o','r','u')]"]])
    ,("x_u9"
    ,Paragraf [Text "Se aplicarmos ",Function "zip3",Text " com apenas um argumento, temos uma função que aceita dois argumentos. Não importa o que nós fornecemos argumentos para esta função compostos, seu primeiro argumento será sempre o valor fixo que especificamos."])
    ,("ch04.list.ghci:zip3foo"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":t zip3 \"foo\""],
             ScMachineResponse ["zip3 \"foo\" :: [b] -&gt; [c] -&gt; [(Char, b, c)]"],
             ScGHCiPrompt,ScUserInput ["let zip3foo= zip3 \"foo\""],
             ScGHCiPrompt,ScUserInput [":t zip3foo"],
             ScMachineResponse ["zip3foo :: [b] -&gt; [c] -&gt; [(Char, b, c)]"],
             ScGHCiPrompt,ScUserInput ["(zip3 \"foo\") \"aaa\" \"bbb\""],
             ScMachineResponse ["[('f','a','b'),('o','a','b'),('o','a','b')]"],
             ScGHCiPrompt,ScUserInput ["zip3foo \"aaa\" \"bbb\""],
             ScMachineResponse ["[('f','a','b'),('o','a','b'),('o','a','b')]"],
             ScGHCiPrompt,ScUserInput ["zip3foo [1,2,3] [True,False,True]"],
             ScMachineResponse ["[('f',1,True),('o',2,False),('o',3,True)]"]])
    ,("x_v9"
    ,Paragraf [Text "Quando passamos menos argumentos para uma função que a função pode aceitar, nós chamamos isso de ",Emphasis "aplicação parcial",Text " da função: estamos aplicando a função a que apenas alguns de seus argumentos."])
    ,("x_w9"
    ,Paragraf [Text "No exemplo acima, temos uma função aplicada parcialmente, ",Code "zip3 \"foo\"",Text ", e uma nova função, ",Function "zip3foo",Text ". Podemos ver que as assinaturas do tipo dois e seu comportamento são idênticos."])
    ,("x_x9"
    ,Paragraf [Text "Isto aplica-se tão bem se fixar dois argumentos, dando-nos uma função de apenas um argumento."])
    ,("ch04.list.ghci:zip3foobar"
    ,Screen [
             ScGHCiPrompt,ScUserInput ["let zip3foobar= zip3 \"foo\" \"bar\""],
             ScGHCiPrompt,ScUserInput [":t zip3foobar"],
             ScMachineResponse ["zip3foobar :: [c] -&gt; [(Char, Char, c)]"],
             ScGHCiPrompt,ScUserInput ["zip3foobar \"quux\""],
             ScMachineResponse ["[('f','b','q'),('o','a','u'),('o','r','u')]"],
             ScGHCiPrompt,ScUserInput ["zip3foobar [1,2]"],
             ScMachineResponse ["[('f','b',1),('o','a',2)]"]])
    ,("x_y9"
    ,Paragraf [Text "Aplicação parcial de função nos permite evitar a criação de funções descartáveis cansativo. Muitas vezes é mais útil para este propósito que as funções anônimas que introduzimos na ",XRef "#fp.anonymous" [XText "seção chamada “Funções (lambda) anónimos”"],Text ". Olhando para trás, a função ",Function "isInAny",Text " nós definimos lá, aqui está como nós usaríamos uma função parcialmente aplicado em vez de uma função auxiliar chamada ou uma lambda."])
    ,("Partial.hs:isInAny3"
    ,Listing [LComment ["-- arquivo: ca04/Parcial.hs"]
             ,LNewline,LText ["isInAny3 needle haystack = any (isInfixOf needle) haystack"]])
    ,("x_z9"
    ,Paragraf [Text "Aqui, a expressão ",Code "isInfixOf needle",Text " é a função aplicada parcialmente. Nós estamos tomando a função ",Function "isInfixOf",Text ", e “",Quote [QText "consertar"],Text "” seu primeiro argumento a ser a variável de ",Varname "needle",Text " de nossa lista de parâmetros. Isso nos dá uma função parcialmente aplicada que tem exatamente o mesmo tipo de comportamento e como o ajudante e lambda em nossas definições anteriores."])
    ,("x_HD1"
    ,Paragraf [Text "Aplicação de função parcial é chamado ",Emphasis "currying",Text ", após o lógico Haskell Curry (para quem a linguagem Haskell é chamado)."])
    ,("x_eL"
    ,Paragraf [Text "Como outro exemplo de currying em uso, vamos voltar para a função lista-resumo que escrevi na ",XRef "#fp.foldl" [XText "seção chamada “A fold esquerda”"],Text "."])
    ,("id596294"
    ,Listing [LComment ["-- arquivo: ca04/Soma.hs"]
             ,LNewline,LText ["somaFina:: [Int]-&gt; Int"
                             ,"somaFina xs = foldl (+) 0 xs"]])
    ,("x_fL"
    ,Paragraf [Text "Nós não precisamos de aplicar plenamente ",Function "foldl",Text ", podemos omitir a lista de ",Varname "xs",Text " tanto a lista de parâmetros e os parâmetros para ",Function "foldl",Text ", e nós vamos acabar com uma função mais compacto que tem o mesmo tipo."])
    ,("Sum.hs:nicerSum"
    ,Listing [LComment       ["-- arquivo: ca04/Soma.hs"]
             ,LNewline,LText ["somaMaisFina:: [Int]-&gt; Int"
                             ,"somaMaisFina = foldl (+) 0"]])
    ,("x_AA"
    ,Paragraf [Text "Haskell fornece um atalho útil para notação vamos escrever uma função parcialmente aplicadas em estilo infixo. Se colocar um operador em parênteses, nós podemos fornecer o seu argumento a esquerda ou direita dentro dos parênteses para obter uma função aplicada parcialmente. Este tipo de aplicação parcial é chamado de ",Emphasis "section",Text "."])
    ,("partial.ghci:section"
    ,Screen [
             ScGHCiPrompt,ScUserInput ["(1+) 2"],
             ScMachineResponse ["3"],
             ScGHCiPrompt,ScUserInput ["map (*3) [24,36]"],
             ScMachineResponse ["[72,108]"],
             ScGHCiPrompt,ScUserInput ["map (2^) [3,5,7,9]"],
             ScMachineResponse ["[8,32,128,512]"]])
    ,("x_BA"
    ,Paragraf [Text "Se nos fornecer o argumento à esquerda dentro da seção, chamando a função resultante com um material argumento argumento do lado direito do operador. E vice-versa."])
    ,("x_CA"
    ,Paragraf [Text "Lembre-se que nós podemos envolver um nome de função em backquotes usá-lo como um operador infixo. Isto nos permite usar seções com funções."])
    ,("partial.ghci:function"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":t (`elem` ['a'..'z'])"],
             ScMachineResponse ["(`elem` ['a'..'z']) :: Char -&gt; Bool"]])
    ,("x_DA"
    ,Paragraf [Text "A definição acima fixa o segundo argumento de ",Function "elem",Text " dando-nos uma função que verifica se seu argumento for uma letra minúscula."])
    ,("partial.ghci:lower.letter"
    ,Screen [
             ScGHCiPrompt,ScUserInput ["(`elem` ['a'..'z']) 'f'"],
             ScMachineResponse ["True"]])
    ,("x_EA"
    ,Paragraf [Text "Usando isso como um argumento para ",Function "all",Text ", temos uma função que verifica uma seqüência inteira para ver se está tudo em minúsculas."])
    ,("partial.ghci:lower.string"
    ,Screen [
             ScGHCiPrompt,ScUserInput ["all (`elem` ['a'..'z']) \"Frobozz\""],
             ScMachineResponse ["False"]])
    ,("x_ID1"
    ,Paragraf [Text "Se usarmos esse estilo, podemos melhorar ainda mais a leitura de nossa função ",Function "isInAny3",Text " anterior."])
    ,("Partial.hs:isInAny4"
    ,Listing [LComment       ["-- arquivo: ca04/Parcial.hs"]
             ,LNewline,LText ["isInAny4 needle haystack = any (needle `isInfixOf`) haystack"]])
    ,("x_FA"
    ,Paragraf [Text "A função Haskell ",Function "tails",Text ", no módulo ",Code "Data.List",Text ", generaliza a função ",Function "tail",Text " foi introduzida recentemente. Em vez de retornar uma “",Quote [QText "cauda"],Text "” da lista, ele retorna ",Emphasis "todos",Text " eles."])
    ,("suffix.ghci:tails"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":m +Data.List"],
             ScGHCiPrompt,ScUserInput ["tail \"foobar\""],
             ScMachineResponse ["\"oobar\""],
             ScGHCiPrompt,ScUserInput ["tail (tail \"foobar\")"],
             ScMachineResponse ["\"obar\""],
             ScGHCiPrompt,ScUserInput ["tails \"foobar\""],
             ScMachineResponse ["[\"foobar\",\"oobar\",\"obar\",\"bar\",\"ar\",\"r\",\"\"]"]])
    ,("x_GA"
    ,Paragraf [Text "Cada uma dessas cadeias é um ",Emphasis "sufixo",Text " de String inicial, para ",Function "tails",Text " produz uma lista de todos os sufixos, além de uma lista vazia extra no final. Ela produz sempre que a lista extra vazio, mesmo quando sua lista de entrada está vazia."])
    ,("suffix.ghci:tails.empty"
    ,Screen [
             ScGHCiPrompt,ScUserInput ["tails []"],
             ScMachineResponse ["[[]]"]])
    ,("x_HA"
    ,Paragraf [Text "E se queremos uma função que se comporta como ",Function "tails",Text ", mas que retorna ",Emphasis "apenas",Text " os sufixos não vazios? Uma possibilidade seria para nós a escrever a nossa própria versão a mão. Vamos usar uma nova peça de notação, o símbolo ",Code "@",Text "."])
    ,("SuffixTree.hs:suffixes"
    ,Listing [LComment ["-- arquivo: ca04/ArvorDeSufixos.hs"]
             ,LNewline,LText ["sufixos:: [a]-&gt; [[a]]"
             ,"sufixos xs@(_:xs') = xs : suffixes xs'"
             ,"sufixos _ = []"]])
    ,("x_JA"
    ,Paragraf [Text "O padrão ",Code "xs@(_:xs')",Text " é chamado um ",Emphasis "padrão as",Text ", e significa “",Quote [QText "ligar o variável ",QVarname "xs",QText " para o valor que corresponda ao lado direito do símbolo ",QCode "@"],Text "”."])
    ,("x_KA"
    ,Paragraf [Text "No nosso exemplo, se o padrão depois do “",Quote [QText "@"],Text "” corresponde, ",Varname "xs",Text " será obrigado a toda a lista que combinava e ",Varname "xs'",Text " para todos, mas o cabeça da lista (usamos o padrão wild card ",Code "_",Text " para indicar que estamos não está interessado no valor do cabeça de lista)."])
    ,("suffix.ghci:suffixes"
    ,Screen [
             ScGHCiPrompt,ScUserInput ["tails \"foo\""],
             ScMachineResponse ["[\"foo\",\"oo\",\"o\",\"\"]"],
             ScGHCiPrompt,ScUserInput ["suffixes \"foo\""],
             ScMachineResponse ["[\"foo\",\"oo\",\"o\"]"]])
    ,("x_LA"
    ,Paragraf [Text "O padrão as torna o código nosso mais legível. Para ver como isso ajuda, vamos comparar uma definição que não tenha um padrão as."])
    ,("SuffixTree.hs:noAsPattern"
    ,Listing [LComment ["-- arquivo: ca04/ArvorDeSufixos.hs"]
             ,LNewline,LText ["semPadrãoAs:: [a]-&gt; [[a]]"
                             ,"semPadrãoAs (x:xs) = (x:xs) : semPadrãoAs xs"
                             ,"semPadrãoAs _ = []"]])
    ,("x_MA"
    ,Paragraf [Text "Aqui, a lista que nós desconstruído no padrão de jogo só fica colocada de volta em conjunto no corpo da função."])
    ,("x_NA"
    ,Paragraf [Text "Padrões as ter um uso mais prático do que a leitura simples: eles podem nos ajudar a compartilhar dados, em vez de copiá-lo. Em nossa definição de ",Function "semPadrãoAs",Text ", quando jogo ",Code "(x:xs)",Text ", vamos construir uma nova cópia dele no corpo da nossa função. Isso nos leva a atribuir um nó nova lista em tempo de execução. Isso pode ser barato, mas não é livre. Em contraste, quando nós definimos ",Function "sufixos",Text ", reutilizadas o valor ",Varname "xs",Text " que nós combinamos com o nosso como padrão. Desde que reutilizar um valor existente, evitamos uma atribuição pouco."])
    ,("x_OA"
    ,Paragraf [Text "Parece uma vergonha para introduzir uma nova função, ",Function "sufixos",Text ", que faz quase a mesma coisa que a função existente ",Function "tails",Text ". Certamente nós podemos fazer melhor?"])
    ,("x_PA"
    ,Paragraf [Text "Lembre-se da função ",Function "init",Text " introduzimos na ",XRef "#fp.lists" [XText "seção chamada “Trabalhar com as listas”"],Text ": retorna todos, mas o último elemento de uma lista."])
    ,("SuffixTree.hs:suffixes2"
    ,Listing [LComment       ["-- arquivo: ca04/ArvorDeSufixos.hs"]
             ,LNewline,LText ["sufixos2 xs = init (tails xs)"]])
    ,("x_QA"
    ,Paragraf [Text "Esta função ",Function "sufixos2",Text " funciona igualmente a ",Function "sufixos",Text ", mas é um única linha de código."])
    ,("suffix.ghci:suffixes2"
    ,Screen [
             ScGHCiPrompt,ScUserInput ["sufixos2 \"foo\""],
             ScMachineResponse ["[\"foo\",\"oo\",\"o\"]"]])
    ,("x_RA"
    ,Paragraf [Text "Se tomarmos um passo para trás, vemos o reflexo de um padrão aqui: nós estamos aplicando uma função, em seguida, aplicar uma outra função para o seu resultado. Vamos transformar esse padrão em uma definição de função."])
    ,("SuffixTree.hs:compose"
    ,Listing [LComment       ["-- arquivo: ca04/ArvorDeSufixos.hs"]
             ,LNewline,LText ["compor:: (b-&gt;c)-&gt; (a-&gt;b)-&gt; a-&gt; c"
             ,"compor f g x = f (g x)"]])
    ,("x_SA"
    ,Paragraf [Text "Agora temos uma função, ",Function "compor",Text ", que podemos usar para “",Quote [QText "cola"],Text "” outras duas funções em conjunto."])
    ,("SuffixTree.hs:suffixes3"
    ,Listing [LComment ["-- arquivo: ca04/ArvorDeSufixos.hs"
             ,"sufixos3 xs = compor init tails xs"]])
    ,("x_TA"
    ,Paragraf [Text "O currying automático do Haskell nos deixa cair a variável ",Varname "xs",Text "para que possamos fazer a nossa definição ainda mais curtos."])
    ,("SuffixTree.hs:suffixes4"
    ,Listing [LComment ["-- arquivo: ca04/ArvorDeSufixos.hs"
             ,"sufixos4 = compor init tails"]])
    ,("x_UA"
    ,Paragraf [Text "Felizmente, não precisamos de escrever a nossa própria função ",Function "compor",Text ". Ligar funções em cada um, como isto é tão comum que a Prelude fornece composição das funções através do operador ",Function "(.)",Text "."])
    ,("SuffixTree.hs:suffixes5"
    ,Listing [LComment ["-- arquivo: ca04/ArvorDeSufixos.hs"
             ,"sufixos5 = init . tails"]])
    ,("x_VA"
    ,Paragraf [Text "O operador ",Function "(.)",Text " não é uma parte especial da sintaxe da linguagem, é apenas um operador normal."])
    ,("suffix.ghci:types"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":t (.)"],
             ScMachineResponse ["(.) :: (b -&gt; c) -&gt; (a -&gt; b) -&gt; a -&gt; c"],
             ScGHCiPrompt,ScUserInput [":t sufixos"],
             ScMachineResponse ["suffixes :: [a] -&gt; [[a]]"],
             ScGHCiPrompt,ScUserInput [":t sufixos5"],
             ScMachineResponse ["suffixes5 :: [a] -&gt; [[a]]"],
             ScGHCiPrompt,ScUserInput ["sufixs5 \"foo\""],
             ScMachineResponse ["[\"foo\",\"oo\",\"o\"]"]])
    ,("x_WA"
    ,Paragraf [Text "Podemos criar novas funções a qualquer momento por escrito cadeias de funções compostas, costurado com ",Function "(.)",Text ", tanto tempo (é claro) como o tipo de resultado da função no lado direito de cada um ",Function "(.)",Text " corresponde ao tipo de parâmetro que o função na esquerda pode aceitar."])
    ,("x_JD1"
    ,Paragraf [Text "Como exemplo, vamos resolver um enigma muito simples: a contagem do número de palavras em uma seqüência que começa com uma letra maiúscula."])
    ,("suffix.ghci:dotty"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":m +Data.Char"],
             ScGHCiPrompt,ScUserInput ["let numeroMaiusc= length . filter (isUpper . head) . words"],
             ScGHCiPrompt,ScUserInput ["numeroMaiusc \"Olá! Olá, mãe!\""],
             ScMachineResponse ["2"]])
    ,("x_KD1"
    ,Paragraf [Text "Podemos entender que esta função é composta pela análise das suas peças. A função ",Function "(.)",Text " é associativa direito, por isso vamos prosseguir da direita para a esquerda."])
    ,("suffix.ghci:words.type"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":t words"],
             ScMachineResponse ["words :: String -&gt; [String]"]])
    ,("x_LD1"
    ,Paragraf [Text "A função ",Function "words",Text " tem um tipo de resultado de ",Type "[String]",Text ", para o que está no lado esquerdo de ",Function "(.)",Text " deve aceitar um argumento compatível."])
    ,("suffix.ghci:capped.type"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":t isUpper . head"],
             ScMachineResponse ["isUpper . head :: [Char] -&gt; Bool"]])
    ,("x_MD1"
    ,Paragraf [Text "Essa função retorna ",Code "True",Text " se uma palavra começa com uma letra maiúscula (testá-lo em ",Command "ghci",Text "), os ",Code "filter (isUpper . head)",Text " retorna uma lista de ",Type "String",Text "s contendo apenas palavras que começam com letras maiúsculas."])
    ,("suffix.ghci:capfilt.type"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":t filter (isUpper . head)"],
             ScMachineResponse ["filter (isUpper . head) :: [[Char]] -&gt; [[Char]]"]])
    ,("x_ND1"
    ,Paragraf [Text "Uma vez que esta expressão retorna uma lista, tudo o que resta é calcular o comprimento da lista, o que fazemos com outra composição."])
    ,("x_XA"
    ,Paragraf [Text "Aqui está outro exemplo, retirado de uma aplicação real. Queremos extrair uma lista de nomes de macro de um arquivo de cabeçalho C acompanha ",Code "libpcap",Text ", uma biblioteca popular pacote de filtragem de rede. O arquivo de cabeçalho contém um grande número de definições da seguinte forma."])
    ,("id597123"
    ,Listing [LText ["#define DLT_EN10MB      1       /* Ethernet (10Mb) */"
                    ,"#define DLT_EN3MB       2       /* Experimental Ethernet (3Mb) */"
                    ,"#define DLT_AX25        3       /* Amateur Radio AX.25 */"]])
    ,("x_OD1"
    ,Paragraf [Text "Nosso objetivo é extrair nomes como ",Code "DLT_EN10MB",Text " e ",Code "DLT_AX25",Text "."])
    ,("dlts.hs:dlts"
    ,Listing [LComment       ["-- arquivo: ca04/dlts.hs"]
             ,LNewline,LText ["import Data.List(isPrefixOf)"
                             ,""
                             ,"dlts:: String-&gt; [String]"
                             ,"dlts= foldr passo [] . lines"]])
    ,("x_YA"
    ,Paragraf [Text "Nós tratamos todo um arquivo como uma String, dividi-lo com ",Function "lines",Text ", em seguida, aplicar ",Code "foldr passo []",Text " para a lista resultante de linhas. A função de auxiliar ",Function "passo",Text " opera em uma única linha."])
    ,("dlts.hs:step"
    ,Listing [LComment       ["-- arquivo: ca04/dlts.hs"]
             ,LNewline,LText ["  where passo l ds"
                             ,"          | \"#define DLT_\" `isPrefixOf` l = palavra2 l : ds"
                             ,"          | otherwise = ds"
                             ,"        palavra2 = head . tail . words"]])
    ,("x_ZA"
    ,Paragraf [Text "Se coincidir com uma definição de macro com a nossa expressão guarda, podemos contras o nome da macro para a cabeça da lista que está retornando, caso contrário, deixamos a lista intocada."])
    ,("x_aA"
    ,Paragraf [Text "Enquanto as funções individuais do corpo de ",Function "palavra2",Text " estão agora familiar para nós, pode levar um pouco de prática para montar uma cadeia de composições como esta. Vamos examinar o processo."])
    ,("x_bA"
    ,Paragraf [Text "Mais uma vez, procede da direita para a esquerda. A primeira função é ",Function "words",Text ". "])
    ,("dlts.ghci:words"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":t words"],
             ScMachineResponse ["words :: String -&gt; [String]"],
             ScGHCiPrompt,ScUserInput ["words \"#define DLT_CHAOS    5\""],
             ScMachineResponse ["[\"#define\",\"DLT_CHAOS\",\"5\"]"]])
    ,("x_cA"
    ,Paragraf [Text "Em seguida, aplicamos ",Code "tail",Text " para o resultado de ",Function "words",Text "."])
    ,("dlts.ghci:drop1"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":t tail"],
             ScMachineResponse ["tail :: [a] -&gt; [a]"],
             ScGHCiPrompt,ScUserInput ["tail [\"#define\",\"DLT_CHAOS\",\"5\"]"],
             ScMachineResponse ["[\"DLT_CHAOS\",\"5\"]"],
             ScGHCiPrompt,ScUserInput [":t tail . words"],
             ScMachineResponse ["tail . words :: String -&gt; [String]"],
             ScGHCiPrompt,ScUserInput ["(tail . words) \"#define DLT_CHAOS    5\""],
             ScMachineResponse ["[\"DLT_CHAOS\",\"5\"]"]])
    ,("x_eA"
    ,Paragraf [Text "Finalmente, aplicando ",Function "head",Text " para o resultado de ",Code "drop 1 . words",Text "  nos dará o nome de nossa macro."])
    ,("dlts.ghci:head.drop1.words"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":t head . tail . words"],
             ScMachineResponse ["head . tail . words :: String -&gt; String"],
             ScGHCiPrompt,ScUserInput ["(head . tail . words) \"#define DLT_CHAOS    5\""],
             ScMachineResponse ["\"DLT_CHAOS\""]])
    ,("x_fA"
    ,Paragraf [Text "Depois da advertência contra lista de funções inseguras na ",XRef "#fp.lists.safe" [XText "seção chamada “Trabalhar segura e saudavelmente a com funções crashy”"],Text ", aqui estamos chamando tanto a ",Function "head",Text " e a ",Function "tail",Text ", duas dessas funções de lista inseguro. O Que Dá?"])
    ,("x_gA"
    ,Paragraf [Text "Neste caso, podemos nos assegurar de inspeção que estamos seguros de uma falha de execução. O guarda padrão na definição de ",Function "passo",Text " contém duas palavras, por isso quando nós aplicamos ",Function "words",Text " a qualquer String de palavras que faz passar pelo guarda, que vamos ter uma lista de pelo menos dois elementos, ",Code "\"#define\"",Text " e alguns macro iniciando com ",Code "\"DLT_\"",Text "."])
    ,("x_hA"
    ,Paragraf [Text "Este tipo de raciocínio que devemos fazer para nos convencermos de que nosso código não vai explodir quando chamamos funções parciais. Não se esqueça nossa admoestação anterior: chamar funções inseguro como este requer cuidados, e muitas vezes pode tornar o código mais frágil de maneira sutil. Se por algum motivo, modificou o padrão de proteção para conter apenas uma palavra, poderíamos nos expor à possibilidade de um acidente, como o corpo da função assume que receberá duas palavras."])
    ,("x_gL"
    ,Paragraf [Text "Até agora, neste capítulo, me deparei com duas características tentador olhar de Haskell: recursão de cauda e funções anônimas. Tão agradável como estes são, muitas vezes não se deseja usá-los."])
    ,("x_hL"
    ,Paragraf [Text "Muitas operações de manipulação de lista pode ser mais facilmente expressos usando combinações de funções de biblioteca, tais como ",Function "map",Text ", ",Function "take",Text ", e ",Function "filter",Text ". Sem dúvida, isto requer alguma prática para se acostumar com estes. No retorno para nosso investimento inicial, podemos ler e escrever código mais rapidamente e com menos bugs."])
    ,("x_iL"
    ,Paragraf [Text "A razão para isso é simples. Uma definição de função recursiva de cauda tem o mesmo problema como um loop em uma linguagem imperativa: é completamente geral. Ele pode realizar alguns filtragem, mapeamento de alguns, ou quem sabe mais o quê. Somos obrigados a olhar em detalhe toda a definição da função para ver o que ele está realmente fazendo. Em contraste, ",Function "map",Text " e funções de manipulação mais outra lista fazer apenas ",Emphasis "uma",Text " coisa. Podemos tomar como garantido que estes blocos de construção simples fazer, e focar na idéia de que o código é tentar expressar, não os mínimos detalhes de como é a manipulação de seus insumos."])
    ,("x_jL"
    ,Paragraf [Text "No meio do caminho entre a cauda funções recursivas (com a generalidade completo) e nossa caixa de ferramentas de funções de manipulação de lista (cada um deles faz uma coisa) encontram-se as dobras. Uma dobra exige mais esforço para entender que, digamos, uma composição de ",Function "map",Text " e ",Function "filter",Text "que faz a mesma coisa, mas ele se comporta de forma mais regular e previsível do que uma função recursiva de cauda. Como regra geral, não use uma dobra se você pode compor algumas funções da biblioteca, mas caso contrário tenta usar uma dobra de preferência à mão-rolados uma loop uma recursiva cauda."])
    ,("x_kL"
    ,Paragraf [Text "Para as funções anônimas, eles tendem a interromper o “",Quote [QText "fluxo"],Text "” de ler um pedaço de código. É muitas vezes tão fácil de escrever uma definição de função local em um cláusula ",Code "let",Text " ou ",Code "where",Text ", e usar isso, como é para colocar uma função anônima em seu lugar. As vantagens relativas de uma função chamada são dois: não precisamos entender a definição da função quando estamos lendo o código que usa-lo, e um nome de função bem escolhido age como um pequeno pedaço de documentação local."])
    ,("x_PD1"
    ,Paragraf [Text "A função ",Function "foldl",Text " que discutimos anteriormente não é o único lugar onde podem ocorrer vazamentos espaço no código Haskell. Vamos usá-lo para ilustrar como a avaliação não-estrita às vezes pode ser problemático, e como resolver as dificuldades que podem surgir."])
    ,("x_QD1"
    ,Paragraf [Text "É perfeitamente razoável para pular esta seção até que você encontrar um space leak “",Quote [QText "in the wild"],Text "”. Desde que você usa ",Function "foldr",Text " se você estiver gerando uma lista, e ",Function "foldl'",Text " em vez de ",Function "foldl",Text " contrário, vazamentos de espaço não são susceptíveis de incomodá-lo na prática por um tempo."])
    ,("x_RD1"
    ,Paragraf [Text "Nós nos referimos a uma expressão que não é avaliada preguiçosamente tão ",Emphasis "rigorosa",Text ", tão ",Function "foldl'",Text " é uma rigorosa deixou desistir. Ele ignora avaliação usual Haskell não-estrita através da utilização de uma função chamada ",Function "seq",Text "."])
    ,("Fold.hs:strict"
    ,Listing [LComment       ["-- arquivo: ca04/Fold.hs"]
             ,LNewline,LText ["foldl' _    zero []     = zero"
                             ,"foldl' passo zero (x:xs) ="
                             ,"    let novo= passo zero x"
                             ,"    in  novo `seq` foldl' passo novo xs"]])
    ,("x_SD1"
    ,Paragraf [Text "Esta função ",Function "seq",Text " tem um tipo peculiar, insinuando que ele não está jogando com as regras habituais."])
    ,("thunky.ghci:seq"
    ,Screen [
             ScGHCiPrompt,ScUserInput [":t seq"],
             ScMachineResponse ["seq :: a -&gt; t -&gt; t"]])
    ,("x_TD1"
    ,Paragraf [Text "Ele funciona da seguinte forma: quando uma expressão ",Function "seq",Text " é avaliada seguintes, ele força o seu primeiro argumento a ser avaliada, em seguida, retorna seu segundo argumento. Na verdade, não fazer nada com o primeiro argumento: ",Function "seq",Text " existe apenas como uma maneira de forçar que o valor a ser avaliada. Vamos caminhar através de uma aplicação breve para ver o que acontece."])
    ,("Fold.hs:step1"
    ,Listing [LComment       ["-- arquivo: ca04/Fold.hs"]
             ,LNewline,LText ["foldl' (+) 1 (2:[])"]])
    ,("x_UD1"
    ,Paragraf [Text "Isso expande o seguinte."])
    ,("Fold.hs:step2"
    ,Listing [LComment       ["-- arquivo: ca04/Fold.hs"]
             ,LNewline,LText ["let novo= 1 + 2"
                             ,"in novo `seq` foldl' (+) novo []"]])
    ,("x_VD1"
    ,Paragraf [Text "O uso de ",Function "seq",Text " avalia forçada ",Varname "novo",Text " a ",Code "3",Text ", e retorna seu segundo argumento."])
    ,("Fold.hs:step3"
    ,Listing [LComment       ["-- arquivo: ca04/Fold.hs"]
             ,LNewline,LText ["foldl' (+) 3 []"]])
    ,("x_WD1"
    ,Paragraf [Text "Acabamos com o resultado seguinte."])
    ,("Fold.hs:step4"
    ,Listing [LComment       ["-- arquivo: ca04/Fold.hs"]
             ,LNewline,LText ["3"]])
    ,("x_XD1"
    ,Paragraf [Text "Graças a ",Function "seq",Text ", não há thunks à vista."])
    ,("x_YD1"
    ,Paragraf [Text "Sem algum sentido, existe um elemento de mistério para usar efetivamente seguintes. Aqui estão algumas regras úteis para usá-lo bem."])
    ,("x_ZD1"
    ,Paragraf [Text "Para ter algum efeito, uma expressão ",Function "seq",Text " devem ser a primeira coisa avaliada em uma expressão."])
    ,("Fold.hs:hiddenInside"
    ,Listing [LComment       ["-- arquivo: ca04/Fold.hs"
                             ,"-- incorreta: seq é escondida pela aplicação de alguma_funcao desde "
                             ,"-- algumaFuncao será avaliada primeiro, seq pode ocorrer muito tarde"]
             ,LNewline,LText ["escondidaDentro x y = algumaFuncao (x `seq` y)"
                             ,""
                             ,"-- incorreta: a variação do erro acima"
                             ,"escondidaParaLet x y z = let a= x `seq` algumaFuncao y"
                             ,"                         in algumaOutraFuncao a z"
                             ,""]
             ,LComment       ["-- correta: seq será avaliada primeiro, forçando avaliação de x"]
             ,LNewline,LText ["emFora x y = x `seq` algumaFuncao y"]])
    ,("x_aD1"
    ,Paragraf [Text "Para estritamente avaliar vários valores, aplicações da cadeia de ",Function "seq",Text " juntos."])
    ,("Fold.hs:chained"
    ,Listing [LComment       ["-- arquivo: ca04/Fold.hs"]
             ,LNewline,LText ["acorrentado x y z = x `seq` y `seq` algumaFuncao z"]])
    ,("x_bD1"
    ,Paragraf [Text "Um erro comum é tentar utilizar ",Function "seq",Text " com duas expressões independentes."])
    ,("Fold.hs:badExpression"
    ,Listing [LComment       ["-- arquivo: ca04/Fold.hs"]
             ,LNewline,LText ["expressãoMau passo zero (x:xs) ="
                             ,"    seq (passo zero x)"
                             ,"        (expressãoMau passo (passo zero x) xs)"]])
    ,("x_cD1"
    ,Paragraf [Text "Aqui, a intenção aparente é o de avaliar estrita ",Code "step zero x",Text ". Uma vez que a expressão é repetido no corpo da função, estritamente avaliar a primeira instância de que não terá nenhum efeito sobre o segundo. A utilização de ",Literal "let",Text " partir da definição de  acima ",Function "foldl'",Text " mostra como conseguir este efeito corretamente."])
    ,("x_dD1"
    ,Paragraf [Text "Ao avaliar uma expressão, ",Function "seq",Text " pára logo que se chega a um construtor. Para os tipos simples, como números, isso significa que irá avaliá-los completamente. tipos de dados algébricos são uma história diferente. Considere o valor ",Code "(1+2):(3+4):[]",Text ". Se aplicarmos ",Function "seq",Text " para isso, vai avaliar o thunk ",Code "(1+2)",Text ". Uma vez que ele irá parar quando atingir o primeiro construtor ",Code "(:)",Text ", ele não terá nenhum efeito sobre a conversão segundo. O mesmo é verdadeiro para tuplas: ",Code "seq ((1+2),(3+4)) True",Text " não fará nada para o thunks dentro do par, uma vez que imediatamente bate construtor do par."])
    ,("x_eD1"
    ,Paragraf [Text "Se necessário, podemos utilizar técnicas habituais de programação funcional para contornar essas limitações."])
    ,("Fold.hs:strictPair"
    ,Listing [LComment       ["-- arquivo: ca04/Fold.hs"]
             ,LNewline,LText ["parEstrito (a,b) = a `seq` b `seq` (a,b)"
             ,""
             ,"listaEstrita (x:xs) = x `seq` x : listaEstrita xs"
             ,"listaEstrita []     = []"]])
    ,("x_fD1"
    ,Paragraf [Text "É importante compreender que a ",Function "seq",Text " não é livre: ele tem que executar uma verificação em tempo de execução para ver se uma expressão foi avaliada. Use com moderação. Por exemplo, enquanto a nossa função ",Function "parEstrito",Text " avalia o conteúdo de um par até o primeiro construtor, ele adiciona as despesas gerais da correspondência padrão, duas aplicações de ",Function "seq",Text ", e da construção de uma nova tupla. Se fôssemos medir o seu desempenho no circuito interno de um referência, podemos encontrá-lo para tornar o programa lento."])
    ,("x_gD1"
    ,Paragraf [Text "Além do seu custo de desempenho se em demasia, ",Function "seq",Text " não é um milagre cura para todos os problemas de consumo de memória. Só porque você ",Emphasis "pode",Text " avaliar algo estritamente não significa que você ",Emphasis "deve",Text ". O uso descuidado do ",Function "seq",Text " podem fazer nada; vazamentos mover espaço existente ao redor, ou introduzir novos vazamentos."])
    ,("x_hD1"
    ,Paragraf [Text "Os melhores guias para se ",Function "seq",Text " é necessário, e como ele funciona, são medidas de desempenho e perfil, a qual será abordada no ",XRef "profiling-and-optimization.html" [XText "Chapter&nbsp;25, ",XCursive "Profiling e ajuste de desempenho"],Text ". A partir de uma base de medição empírica, você irá desenvolver um senso de confiança de quando ",Function "seq",Text " é mais útil."])
  ])