<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
  <title>agaelebe - Home</title>
  <id>tag:www.agaelebe.com.br,2009:mephisto/</id>
  <generator version="0.8.0" uri="http://mephistoblog.com">Mephisto Drax</generator>
  <link href="http://www.agaelebe.com.br/feed/atom.xml" rel="self" type="application/atom+xml"/>
  <link href="http://www.agaelebe.com.br/" rel="alternate" type="text/html"/>
  <updated>2008-12-30T17:40:26Z</updated>
  <entry xml:base="http://www.agaelebe.com.br/">
    <author>
      <name>agaelebe</name>
    </author>
    <id>tag:www.agaelebe.com.br,2008-12-30:36</id>
    <published>2008-12-30T17:21:00Z</published>
    <updated>2008-12-30T17:40:26Z</updated>
    <category term="Ideias"/>
    <category term="acordo ortogr&#225;fico"/>
    <category term="ortografia"/>
    <category term="portug&#234;s"/>
    <link href="http://www.agaelebe.com.br/2008/12/30/acordo-ortografico-2009-com-diferentes-ideias" rel="alternate" type="text/html"/>
    <title>Acordo ortogr&#225;fico - 2009 com diferentes ideias</title>
<content type="html">
            &lt;p&gt;No próximo dia primeiro &lt;em&gt;estreia&lt;/em&gt; o acordo ortográfico da Língua Porguesa. Procurei alguns recursos na Web para realizar a conversão de um texto para o novo acordo. Não irei &lt;em&gt;arguir&lt;/em&gt; neste espaço dizendo se o acordo é bom ou ruim. &lt;em&gt;Abençoo&lt;/em&gt; para que a mudança seja positiva! :) Talvez ela seja irrelevante para uma grande massa de brasileiros &lt;em&gt;semianalfabetos&lt;/em&gt;. Grandes conhecedores da língua portuguesa, como Evanildo Bechara, &lt;em&gt;creem&lt;/em&gt; que as treze regras para emprego do hífen poderiam ser reduzidas.&lt;/p&gt;

&lt;p&gt;Estou pensando em criar um script para realizar a conversão de textos para que eles passem a considerar o acordo ortográfico. Basicamente este script poderia agir de duas maneiras:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Realizar um simples &#8220;encontre e substitua&#8221; (find and replace) utilizando o dicionário do Vero (veja link abaixo). Para isso eu teria de entender um pouco como tal dicionário é usado pelo programa.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ser um pouco mais inteligente e conseguir detectar algumas paroxítonas, ditongos, hífens e realizar as substituições necessárias. Claro que seria difícil tornar um programa deste a prova de falhas. Mas se ele cobrisse as palavras mais usadas, já estaria muito bom. É um bom exercício de expressões regulares. O conversor do Interney parece trabalhar deste modo.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Recursos para entender o Acordo Ortográfico&lt;/h2&gt;

&lt;p&gt;Se você ainda não entende bem o que é o acordo, separei estes recursos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;http://www.portaldalinguaportuguesa.org/index.php?action=acordo&amp;amp;amp;version=1990&quot;&gt;Texto integral do Acordo Ortográfico de 1990&lt;/a&gt; - Sim, foi feito em 1990 e só depois de 19 anos entrará em vigor.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;http://michaelis.uol.com.br/novaortografia.html&quot;&gt;Guia Prático do dicionário Michaelis em HTML&lt;/a&gt; - Versão reduzida do guia em PDF.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;http://images.ig.com.br/hotsites/reforma_ortografica/Guia_Reforma_Ortografica_CP.pdf&quot;&gt;Guia Prático do dicionário Michaelis em PDF&lt;/a&gt; - Guia com 32 páginas explica as principais mudanças no acordo ortográfico. Autoria de Douglas Tufano e publicado pela editora Melhoramentos.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;http://pt.wikipedia.org/wiki/Acordo_Ortogr%C3%A1fico_de_1990&quot;&gt;Wikipédia explica o Acordo Ortográfico&lt;/a&gt; - Note que a própria página do acordo ortográfico ainda não segue o mesmo.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;http://pessoas.hsw.uol.com.br/reforma-ortografica.htm&quot;&gt;HowStuffWorks&lt;/a&gt; (como tudo funciona) explica resumidamente o acordo ortográfico. O site inclusive tem um quiz para testar se você aprendeu as mudanças.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;http://www.broffice.org/verortografico/baixar&quot;&gt;Vero&lt;/a&gt; - Verificador ortográfico para o BrOffice (OpenOffice brasileiro). Disponível para as versões 3.0 e 2.x. Incluindo um dicionário com 9 milhões de palavras tanto para portuguẽs do Brasil quanto português de Portugal (as diferenças entre as línguas diminuíram mas ainda não se extinguiram).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;http://www.interney.net/conversor-ortografico.php&quot;&gt;Conversor ortográfico Interney&lt;/a&gt; - Página em PHP que faz a conversão de um texto em português para a nova grafia. Realizei testes simples de palavras com acentos e hífen e as conversões foram feitas corretamente.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A Microsoft ficou para trás desta vez. Com o prazo de 4 anos para adoção das mudanças não sabemos se sairá uma atualização para o Office 2007 e 2003. A empresa &lt;a href=&quot;http://blogs.technet.com/forum_de_terminologia_ptb/archive/2008/12/05/novas-regras-ortogr-ficas-nos-produtos-da-microsoft.aspx&quot;&gt;só confirmou&lt;/a&gt; que as mudanças estarão nas próximas versões do Windows e Office (Windows 7 e Office 13).&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.agaelebe.com.br/">
    <author>
      <name>agaelebe</name>
    </author>
    <id>tag:www.agaelebe.com.br,2008-12-27:25</id>
    <published>2008-12-27T20:28:00Z</published>
    <updated>2008-12-28T02:24:46Z</updated>
    <category term="Ruby"/>
    <category term="Tradu&#231;&#245;es"/>
    <category term="ia"/>
    <category term="paipr"/>
    <link href="http://www.agaelebe.com.br/2008/12/27/traducao-paipr-o-resolvedor-de-problemas-gerais-parte-1" rel="alternate" type="text/html"/>
    <title>Tradu&#231;&#227;o - PAIPR - O Resolvedor de problemas gerais (parte 1)</title>
<content type="html">
            &lt;p&gt;Continuando a série de traduções dos artigos do Ola Bini, traduzirei a seguir &lt;a href=&quot;http://olabini.com/blog/2008/09/the-general-problem-solver-part-1/&quot;&gt;este artigo&lt;/a&gt;. Posso demorar um pouco, mas pretendo traduzir todos os artigos da série.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;O Resolvedor de problemas gerais, Parte 1&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Para uma das primeiras tentativas de se criar um sistema de resolução de problemas foi dado o grandioso nome de Resolvedor de Problemas Gerais (General Problem Solver). Foi desenvolvido em 1957 por Alan Newell e Herbert Simon. Quando o RPG foi inicialmente apresentado, este causou bastante agitação na comunidade de IA. Porém o RPG não sobreviveu a suas expectativas, mesmo assim é bastante importante do ponto de vista histórico. A implementação orginal do GPS foi escrita em IPL e tem algumas diferenças sutis em relação ao programa desenvolvido no livro PAIP.
Eu seguirei a versão do PAIP enquanto estiver desenvolvendo a versão em Ruby. Se você tem algum interesse na versão original, sugiro que primeiro encontre um livro sobre IPL (que, de maneira alguma, é uma linguagem divertida).&lt;/p&gt;

&lt;p&gt;O RPG implementa uma versão de algo chamado análise de meios e fins. O tipo de pensamento abordado por essa análise é de bastante senso comum. Resumidamente, você tem alguns objetivos, você então deve descobrir quais condições necessitam ser verdadeiras para que você atinja um determinado objetivo. Se estas condições não são verdadeiras, você terá que descobrir como atinji-las, e assim por diante.&lt;/p&gt;

&lt;p&gt;A maneira que escreveremos a primeira versão do GPS possui algumas propriedades interessantes. As principais são o estado inicial, os objetivos e as operaçõs disponíveis. Por enquanto representarei os estados e objetivos como símbolos. Uma operação precisa ser um pouco mais complicada. Em primeiro lugar, ela possui um nome para que você possa rastreá-la. Ela possui pré-condições que detalham o que precisa ser verdadeiro para que essa operação possa ocorrer. E ela possui uma lista de adições e uma lista de remoções. A lista de adições nos diz quais condições são verdadeiras após a execução da operação e a lista de remoções detalha o que já não é mais verdadeiro.&lt;/p&gt;

&lt;p&gt;Então vamos dar uma olhada na primeira versão da implementação. Eu fiz algumas mudanças se comparado ao código Lisp de Norvig. A mais óbvia é que não estou usando variáveis globais. Ao invés delas, opto por colocar tudo em uma classe chamada GPS (este código pode ser encontrado em &lt;a href=&quot;http://github.com/olabini/paipr/tree/master/lib/ch04/gps.rb?raw=true&quot;&gt;lib/ch04/gps.rb&lt;/a&gt; ).&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;TypeName&quot;&gt;GPS&lt;/span&gt;
  &lt;span class=&quot;Variable&quot;&gt;Op&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;LibraryClassType&quot;&gt;Struct&lt;/span&gt;.&lt;span class=&quot;FunctionName&quot;&gt;new&lt;/span&gt;(&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;action&lt;/span&gt;, &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;preconds&lt;/span&gt;, &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;add_list&lt;/span&gt;, &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;del_list&lt;/span&gt;)

  &lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;initialize&lt;/span&gt;(&lt;span class=&quot;FunctionArgument&quot;&gt;state&lt;span class=&quot;FunctionArgument&quot;&gt;,&lt;/span&gt; ops&lt;/span&gt;)
    &lt;span class=&quot;Variable&quot;&gt;&lt;span class=&quot;Variable&quot;&gt;@&lt;/span&gt;state&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; state
    &lt;span class=&quot;Variable&quot;&gt;&lt;span class=&quot;Variable&quot;&gt;@&lt;/span&gt;ops&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; ops
  &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;Comment&quot;&gt;  &lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; Interface prinicipal do Resolvedor de Problemas Gerais: &lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;  &lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; atinge todos os objetivos (goals)&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;  &lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; usando as operações definidas&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;solve&lt;/span&gt;(&lt;span class=&quot;FunctionArgument&quot;&gt;&lt;span class=&quot;Keyword&quot;&gt;*&lt;/span&gt;goals&lt;/span&gt;)
    goals.&lt;span class=&quot;FunctionName&quot;&gt;all?&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;do &lt;/span&gt;|&lt;span class=&quot;Variable&quot;&gt;goal&lt;/span&gt;|
      achieve goal
    &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;Comment&quot;&gt;  &lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; Um objetivo é atingido se ele já foi &lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;  &lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; atingido ou se há uma operação &lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;  &lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; apropriada que seja aplicável a ele&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;achieve&lt;/span&gt;(&lt;span class=&quot;FunctionArgument&quot;&gt;goal&lt;/span&gt;)
    &lt;span class=&quot;Variable&quot;&gt;&lt;span class=&quot;Variable&quot;&gt;@&lt;/span&gt;state&lt;/span&gt;.&lt;span class=&quot;FunctionName&quot;&gt;include?&lt;/span&gt;(goal) &lt;span class=&quot;Keyword&quot;&gt;||&lt;/span&gt;
      (&lt;span class=&quot;Variable&quot;&gt;&lt;span class=&quot;Variable&quot;&gt;@&lt;/span&gt;ops&lt;/span&gt;.&lt;span class=&quot;FunctionName&quot;&gt;find_all&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;do &lt;/span&gt;|&lt;span class=&quot;Variable&quot;&gt;op&lt;/span&gt;|
         &lt;span class=&quot;FunctionName&quot;&gt;appropriate?&lt;/span&gt;(goal, op)
       &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;.&lt;span class=&quot;FunctionName&quot;&gt;any?&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;do &lt;/span&gt;|&lt;span class=&quot;Variable&quot;&gt;op&lt;/span&gt;|
         &lt;span class=&quot;FunctionName&quot;&gt;apply&lt;/span&gt;(op)
       &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;)
  &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;Comment&quot;&gt;  &lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; Uma operação é apropriada para um &lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;  &lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; objetivo se ela está na lista de adições&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;appropriate?&lt;/span&gt;(&lt;span class=&quot;FunctionArgument&quot;&gt;goal&lt;span class=&quot;FunctionArgument&quot;&gt;,&lt;/span&gt; op&lt;/span&gt;)
    op.&lt;span class=&quot;FunctionName&quot;&gt;add_list&lt;/span&gt;.&lt;span class=&quot;FunctionName&quot;&gt;include?&lt;/span&gt;(goal)
  &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;Comment&quot;&gt;  &lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; Imprime uma mensagem e atualiza o estado&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;  &lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; caso a operação seja aplicável&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;apply&lt;/span&gt;(&lt;span class=&quot;FunctionArgument&quot;&gt;op&lt;/span&gt;)
    &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; op.&lt;span class=&quot;FunctionName&quot;&gt;preconds&lt;/span&gt;.&lt;span class=&quot;FunctionName&quot;&gt;all?&lt;/span&gt; { |&lt;span class=&quot;Variable&quot;&gt;cond&lt;/span&gt;| &lt;span class=&quot;FunctionName&quot;&gt;achieve&lt;/span&gt;(cond) }
      puts &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;Executing &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;#{&lt;/span&gt;op&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;FunctionName&quot;&gt;action&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;String&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;Variable&quot;&gt;&lt;span class=&quot;Variable&quot;&gt;@&lt;/span&gt;state&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;-=&lt;/span&gt; op.&lt;span class=&quot;FunctionName&quot;&gt;del_list&lt;/span&gt;
      &lt;span class=&quot;Variable&quot;&gt;&lt;span class=&quot;Variable&quot;&gt;@&lt;/span&gt;state&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;+=&lt;/span&gt; op.&lt;span class=&quot;FunctionName&quot;&gt;add_list&lt;/span&gt;
      &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;BuiltInConstant&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;BuiltInConstant&quot;&gt;false&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Existem alguns componentes neste código, portanto vamos olhar peça por peça. Em primeiro lugar, criamos uma classe chamada GPS. Dentro dela, imediatamente definimos uma estrutura (Struct) chamada Op. Existe uma simetria entre a operação do Lisp defstruct e a chamada Struct.new do Ruby que muito me aprecia. Neste caso ela é perfeita já que nós não queremos que Op tenha nenhum comportamento neste momento. A Op consiste em uma ação, nas pré-condições, na lista de adições e na lista de remoções.&lt;/p&gt;

&lt;p&gt;O método initialize recebe o estado atual e as operações disponíveis (ops). O estado atual é um array de estados e ops é um array de ops.&lt;/p&gt;

&lt;p&gt;A peça central neste código é na verdade o método solve (resolver). Este método corresponde a função GPS no código original. A principal diferença é que a função GPS recebe o estado, os objetivos e as ops como parâmetros, enquanto nós colocamos estes dentro do objeto usando o método initialize.&lt;/p&gt;

&lt;p&gt;Então o que significa para nós resolver os objetivos? Basicamente nós tentamos atingir todos objetivos. Se pudermos atingir todos objetivos nós conseguimos resolvê-los, caso contrário não conseguimos. O código Lisp de Norvig lida com isso um pouco diferente, retornando o símbolo &#8216;resolvido&#8217; caso ele funcione. Ao invés disso, eu resolvi apenas retornar um booleano. Isso significa que nosso uso do método solve pode ser um pouco mais verboso.&lt;/p&gt;

&lt;p&gt;O método achieve (alcançar) tenta fazer duas coisas diferentes. Em primeiro lugar ele checa para saber se o estado atual já inclui o objetivo. Neste caso estamos bem. Caso contrário primeiro precisaremos encontrar todas as operações que são apropriadas para esse objetivo e então checar se alguma destas operações pode ser aplicada. Antes de olhar para os métodos appropriate? e apply, é interessante notar que eu decidi usar o any? (algum) aqui, enquanto Norvig usa a função chamada some (alguns). Estas duas operaçãos são na verdade um pouquinho diferentes, mas por enquanto essa diferença não é importante. A diferença é que enquanto o any? sempre retornára verdadeiro ou falso, o some retornará o valor não-nulo gerado pelo método test. O Ruby não parecer ter nada parecido com isso (Enumerable#detect/find retorna o valor original, não o valor gerado pelo bloco). Como você verá no próximo artigo (parte 2) eu terei que implementar o some nesse ponto.&lt;/p&gt;

&lt;p&gt;O que é o método appropriate? (apropriado) então? Em primeiro lugar, é um método que provavelmente deve pertencer a classe Op no lugar da classe GPS. No momento ele apenas checa se a lista de adições das operações inclui o objetivo - o que significa que tal operação pode ser usada para se alcançar o objetivo.&lt;/p&gt;

&lt;p&gt;Finalmente temos o método apply (aplicar, chamado de apply-op no código de Norvig). O Apply é o local onde os elementos recursivos do algoritmo entram em jogo. Basicamente, para que uma operação seja aplicada, todas as pré-condições desta operação precisam ser compridas. Usamos all? para tentar atinger todas a pré-condições e se le é bem sucedido imprimimos quais ações foram executadas, modificamos o estado removendo a lista de remoção e adicionado a lista de adição e, finalmente, retornamos true.&lt;/p&gt;

&lt;p&gt;E é realmente isso o que há no resolvedor de problemas gerais. É claro que deveríamos testá-lo e ver, certo? O domínio comum de uso do GPS era o de guiar até a enfermaria e nós vamos usar algo similar a isso para testar esta implementação.&lt;/p&gt;

&lt;p&gt;A primeira coisa que precisamos é ter algumas operações definidas para este domínio. Você também  pode encontrar esse código em (http://github.com/olabini/paipr/tree/master/lib/ch04/gps.rb?raw=true)[lib/ch04/gps.rb]:&lt;/p&gt;

&lt;p&gt;SCHOOL_OPS = [
                Op.new(:drive&lt;em&gt;son&lt;/em&gt;to_school,
                       [:son&lt;em&gt;at_home, :car&lt;/em&gt;works],
                       [:son_at_school],
                       [:son_at_home]),
                Op.new(:shop&lt;em&gt;installs&lt;/em&gt;battery,
                       [:car&lt;em&gt;needs&lt;/em&gt;battery, :shop&lt;em&gt;knows&lt;/em&gt;problem,
                        :shop&lt;em&gt;has&lt;/em&gt;money],
                       [:car_works],
                       []),
                Op.new(:tell&lt;em&gt;shop&lt;/em&gt;problem,
                       [:in&lt;em&gt;communication&lt;/em&gt;with_shop],
                       [:shop&lt;em&gt;knows&lt;/em&gt;problem],
                       []),
                Op.new(:telephone_shop,
                       [:know&lt;em&gt;phone&lt;/em&gt;number],
                       [:in&lt;em&gt;communication&lt;/em&gt;with_shop],
                       []),
                Op.new(:look_up_number,
                       [:have&lt;em&gt;phone&lt;/em&gt;book],
                       [:know&lt;em&gt;phone&lt;/em&gt;number],
                       []),
                Op.new(:give&lt;em&gt;shop&lt;/em&gt;money,
                       [:have_money],
                       [:shop&lt;em&gt;has&lt;/em&gt;money],
                       [:have_money])
               ]&lt;/p&gt;

&lt;p&gt;&amp;lt;/filter:code&gt;&lt;/p&gt;

&lt;p&gt;Como você pode ver, este domínio dá uma dica sobre o que pode entrar em jogo nos objetivos do domínio. Então, vamos começar dando uma olhada nos problemas em questão. O primeiro problema está em [lib/ch04/problem1.rb]():&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;gps&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;&lt;/span&gt;

gps &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;Variable&quot;&gt;GPS&lt;/span&gt;.&lt;span class=&quot;FunctionName&quot;&gt;new&lt;/span&gt;([&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;son_at_home&lt;/span&gt;,
               &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;car_needs_battery&lt;/span&gt;,
               &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;have_money&lt;/span&gt;,
               &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;have_phone_book&lt;/span&gt;],
              &lt;span class=&quot;Variable&quot;&gt;GPS&lt;/span&gt;::&lt;span class=&quot;FunctionName&quot;&gt;SCHOOL_OPS&lt;/span&gt;)
&lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; gps.&lt;span class=&quot;FunctionName&quot;&gt;solve&lt;/span&gt;(&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;son_at_school&lt;/span&gt;)
  puts &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;Solved&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;else&lt;/span&gt;
  puts &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;Not solved&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;O estado atual diz que o filho está em casa, o carro precisa de uma bateria e que nós temos dinheiro e uma lista telefônica. O objetivo a se alcançar é levar o filho até a escola. Se executarmos este código ele gera a seguinte saída:&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
&lt;span class=&quot;Variable&quot;&gt;Executing&lt;/span&gt; look_up_number
&lt;span class=&quot;Variable&quot;&gt;Executing&lt;/span&gt; telephone_shop
&lt;span class=&quot;Variable&quot;&gt;Executing&lt;/span&gt; tell_shop_problem
&lt;span class=&quot;Variable&quot;&gt;Executing&lt;/span&gt; give_shop_money
&lt;span class=&quot;Variable&quot;&gt;Executing&lt;/span&gt; shop_installs_battery
&lt;span class=&quot;Variable&quot;&gt;Executing&lt;/span&gt; drive_son_to_school
&lt;span class=&quot;Variable&quot;&gt;Solved&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Bem, isso parece ter funcionado corretamente, certo? E no caso em que não temos nenhuma lista telefônica?
(lib/ch04/problem2.rb):&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;gps&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;&lt;/span&gt;

gps &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;Variable&quot;&gt;GPS&lt;/span&gt;.&lt;span class=&quot;FunctionName&quot;&gt;new&lt;/span&gt;([&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;son_at_home&lt;/span&gt;,
               &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;car_needs_battery&lt;/span&gt;,
               &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;have_money&lt;/span&gt;],
              &lt;span class=&quot;Variable&quot;&gt;GPS&lt;/span&gt;::&lt;span class=&quot;FunctionName&quot;&gt;SCHOOL_OPS&lt;/span&gt;)

&lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; gps.&lt;span class=&quot;FunctionName&quot;&gt;solve&lt;/span&gt;(&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;son_at_school&lt;/span&gt;)
  puts &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;Solved&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;else&lt;/span&gt;
  puts &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;Not solved&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;Variable&quot;&gt;Isso&lt;/span&gt; gera:

&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;LibraryFunction&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;code&lt;/span&gt; lang&lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;ruby&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;Variable&quot;&gt;Not&lt;/span&gt; solved
&lt;/pre&gt;

&lt;p&gt;como esperávamos. E se pegarmos um exemplo bem simples em que o carro já funciona  (lib/ch04/problem3.rb):&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;gps&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;&lt;/span&gt;

gps &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;Variable&quot;&gt;GPS&lt;/span&gt;.&lt;span class=&quot;FunctionName&quot;&gt;new&lt;/span&gt;([&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;son_at_home&lt;/span&gt;,
               &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;car_works&lt;/span&gt;],
              &lt;span class=&quot;Variable&quot;&gt;GPS&lt;/span&gt;::&lt;span class=&quot;FunctionName&quot;&gt;SCHOOL_OPS&lt;/span&gt;)

&lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; gps.&lt;span class=&quot;FunctionName&quot;&gt;solve&lt;/span&gt;(&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;son_at_school&lt;/span&gt;)
  puts &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;Solved&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;else&lt;/span&gt;
  puts &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;Not solved&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Obtemos:&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
&lt;span class=&quot;Variable&quot;&gt;Executing&lt;/span&gt; drive_son_to_school
&lt;span class=&quot;Variable&quot;&gt;Solved&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Legal. Parece bom. Então quais são os problemas com a abordagem atual? Em primeirlo lugar, ela não resolve alguns problemas bem fáceis. A representação é em geral incorreta para atividades contínuas. Norvig chama esse problema de &#8220;correndo ao redor do quarteirão&#8221;. É fácil definir um objetivo de dirigir de casa para a escola, mas é um pouco mais complicado representar uma corrida ao redor do quarteirão. Existem modos de fazê-lo, claro, mas o operador GPS não os tornam necessariamente naturais como poderiam ser.&lt;/p&gt;

&lt;p&gt;Outro problema mais sério é o problema do objetivo do irmão derrotado. No lib/ch04/problem4.rb a versão do GPS lida com tudo corretamente:&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;gps&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;&lt;/span&gt;

gps &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;Variable&quot;&gt;GPS&lt;/span&gt;.&lt;span class=&quot;FunctionName&quot;&gt;new&lt;/span&gt;([&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;son_at_home&lt;/span&gt;,
               &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;have_money&lt;/span&gt;,
               &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;car_works&lt;/span&gt;],
              &lt;span class=&quot;Variable&quot;&gt;GPS&lt;/span&gt;::&lt;span class=&quot;FunctionName&quot;&gt;SCHOOL_OPS&lt;/span&gt;)

&lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; gps.&lt;span class=&quot;FunctionName&quot;&gt;solve&lt;/span&gt;(&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;have_money&lt;/span&gt;, &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;son_at_school&lt;/span&gt;)
  puts &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;Solved&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;else&lt;/span&gt;
  puts &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;Not solved&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Mas se criarmos um problema como este (lib/ch04/problem5.rb):&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;gps&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;&lt;/span&gt;

gps &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;Variable&quot;&gt;GPS&lt;/span&gt;.&lt;span class=&quot;FunctionName&quot;&gt;new&lt;/span&gt;([&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;son_at_home&lt;/span&gt;,
               &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;car_needs_battery&lt;/span&gt;,
               &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;have_phone_book&lt;/span&gt;,
               &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;have_money&lt;/span&gt;],
              &lt;span class=&quot;Variable&quot;&gt;GPS&lt;/span&gt;::&lt;span class=&quot;FunctionName&quot;&gt;SCHOOL_OPS&lt;/span&gt;)

&lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; gps.&lt;span class=&quot;FunctionName&quot;&gt;solve&lt;/span&gt;(&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;have_money&lt;/span&gt;, &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;son_at_school&lt;/span&gt;)
  puts &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;Solved&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;else&lt;/span&gt;
  puts &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;Not solved&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Isto será incorretamente reportado como resolvido - já que o GPS resolve primeiro o problema de termos dinheiro, então resolve o problema de termos o filho na escola. O modo de lidarmos com esse problema é substuirmos cada instância que atinge cada chamada com uma chamada para um novo método chamado achieve&lt;em&gt;all (alcança tudo). Isso envolve os métodos solve e apply. você pode ver este código em lib/ch04/gps&lt;/em&gt;no_clobber.rb:&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;gps&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;TypeName&quot;&gt;Array&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;subset_of?&lt;/span&gt;(&lt;span class=&quot;FunctionArgument&quot;&gt;other&lt;/span&gt;)
    (&lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;-&lt;/span&gt; other) &lt;span class=&quot;Keyword&quot;&gt;==&lt;/span&gt; []
  &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;TypeName&quot;&gt;GPS&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;solve&lt;/span&gt;(&lt;span class=&quot;FunctionArgument&quot;&gt;&lt;span class=&quot;Keyword&quot;&gt;*&lt;/span&gt;goals&lt;/span&gt;)
    achieve_all goals
  &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;apply&lt;/span&gt;(&lt;span class=&quot;FunctionArgument&quot;&gt;op&lt;/span&gt;)
    &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;achieve_all&lt;/span&gt;(op.&lt;span class=&quot;FunctionName&quot;&gt;preconds&lt;/span&gt;)
      puts &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;Executing &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;#{&lt;/span&gt;op&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;FunctionName&quot;&gt;action&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;String&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;Variable&quot;&gt;&lt;span class=&quot;Variable&quot;&gt;@&lt;/span&gt;state&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;-=&lt;/span&gt; op.&lt;span class=&quot;FunctionName&quot;&gt;del_list&lt;/span&gt;
      &lt;span class=&quot;Variable&quot;&gt;&lt;span class=&quot;Variable&quot;&gt;@&lt;/span&gt;state&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;+=&lt;/span&gt; op.&lt;span class=&quot;FunctionName&quot;&gt;add_list&lt;/span&gt;
      &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;BuiltInConstant&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;BuiltInConstant&quot;&gt;false&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;achieve_all&lt;/span&gt;(&lt;span class=&quot;FunctionArgument&quot;&gt;goals&lt;/span&gt;)
    goals.&lt;span class=&quot;FunctionName&quot;&gt;all?&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;do &lt;/span&gt;|&lt;span class=&quot;Variable&quot;&gt;goal&lt;/span&gt;|
      achieve goal
    &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; goals.&lt;span class=&quot;FunctionName&quot;&gt;subset_of?&lt;/span&gt;(&lt;span class=&quot;Variable&quot;&gt;&lt;span class=&quot;Variable&quot;&gt;@&lt;/span&gt;state&lt;/span&gt;)
  &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Aqui eu apenas decidi abrir a classe GPS para prover esta nova funcionalidade. Outra opção seria criar uma subclasse, mas já que isso substancialmente não altera a funcionalidade, decici apenas fazer deste modo. Existem algumas coisas acontecendo neste código. Primeiro decidi adicionar um operador a classe Array, que se espelha na função susetp do Common Lisp. Array.subset&lt;em&gt;of? retorna verdadeiro se o array atual é um subconjunto do array de argumentos, então [].subset&lt;/em&gt;of?([1]) == true, enquanto [1].subset&lt;em&gt;of?([]) == false. O método solve é atualizado para apenas chamar o achieve&lt;/em&gt;all,  e apply também chama achieva&lt;em&gt;all. A definição do método achieve&lt;/em&gt;all primeiro tem certeza de que podemos atingir todos objetivos e então tem certeza de que todos outros objetivos a se atingir ainda estão no estado atual.&lt;/p&gt;

&lt;p&gt;Se você executar lib/ch04/problem6.rb:&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;gps_no_clobber&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;&lt;/span&gt;

gps &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;Variable&quot;&gt;GPS&lt;/span&gt;.&lt;span class=&quot;FunctionName&quot;&gt;new&lt;/span&gt;([&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;son_at_home&lt;/span&gt;,
               &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;car_needs_battery&lt;/span&gt;,
               &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;have_phone_book&lt;/span&gt;,
               &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;have_money&lt;/span&gt;],
              &lt;span class=&quot;Variable&quot;&gt;GPS&lt;/span&gt;::&lt;span class=&quot;FunctionName&quot;&gt;SCHOOL_OPS&lt;/span&gt;)

&lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; gps.&lt;span class=&quot;FunctionName&quot;&gt;solve&lt;/span&gt;(&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;have_money&lt;/span&gt;, &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;son_at_school&lt;/span&gt;)
  puts &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;Solved&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;else&lt;/span&gt;
  puts &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;Not solved&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Verá que ele executa algumas ações mas então retorna um não resolvido, já que não é possível atingir ambos objetivos.&lt;/p&gt;

&lt;p&gt;Outro problema com esta implementação é baseado na intercalação entre planejamento e execução. Norvig chama isso de &#8220;o problema de saltar antes de olhar&#8221;. Você pode ver um exemplo deste problema na última execução - isto é, vemos que fizemos várias coisas, mas então percebemos que não podemos resolver o problema. No final da execução nos já consertamos o carro dando o dinheiro a oficina. Isso pode não ter sido muito bom. Já que nós temos apenas uma variável de estado, e isto já foi alterado, não há como voltarmos atrás.&lt;/p&gt;

&lt;p&gt;Há um problema final, com subobjetivos recursivos. Isto é, esta versão do GPS não é tão boa em lidar com um caso em que o objetivo depende de outro objetivo que depende do primeiro. O arquivo  lib/ch04/problem7.rb exemplifica isso:&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;gps&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;&lt;/span&gt;

gps &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;Variable&quot;&gt;GPS&lt;/span&gt;.&lt;span class=&quot;FunctionName&quot;&gt;new&lt;/span&gt;([&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;son_at_home&lt;/span&gt;,
               &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;car_needs_battery&lt;/span&gt;,
               &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;have_money&lt;/span&gt;],
              &lt;span class=&quot;Variable&quot;&gt;GPS&lt;/span&gt;::&lt;span class=&quot;FunctionName&quot;&gt;SCHOOL_OPS&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;+&lt;/span&gt;
              [
               &lt;span class=&quot;Variable&quot;&gt;GPS&lt;/span&gt;::&lt;span class=&quot;FunctionName&quot;&gt;Op&lt;/span&gt;.&lt;span class=&quot;FunctionName&quot;&gt;new&lt;/span&gt;(&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;ask_phone_number&lt;/span&gt;,
                           [&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;in_communication_with_shop&lt;/span&gt;],
                           [&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;know_phone_number&lt;/span&gt;],
                           [])
              ])

&lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; gps.&lt;span class=&quot;FunctionName&quot;&gt;solve&lt;/span&gt;(&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;son_at_school&lt;/span&gt;)
  puts &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;Solved&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;else&lt;/span&gt;
  puts &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;Not solved&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Nós removemos o estado :have&lt;em&gt;phone&lt;/em&gt;book do estado inicial e adicionamos uma nova operação para pedir pelo número de telefone. Esta operação requer que você entre em contato com a oficina e, já que você precisa do número de telefone para isso, isso resultará num SystemStackError (erro de pilha do sistema) no Ruby.&lt;/p&gt;

&lt;p&gt;Uma última perturbação com a implementação atual é que ela apenas diz verdadeiro ou falso. A única informação que recebemos é a saída impressa na tela.&lt;/p&gt;

&lt;p&gt;Tudo isso são coisas que a versão final do GPS irá lidar mais corretamente - pelo menos em alguns casos.
Este artigo já está sufcientemente longo, então o GPS2 terá que esperar para o próximo!&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.agaelebe.com.br/">
    <author>
      <name>agaelebe</name>
    </author>
    <id>tag:www.agaelebe.com.br,2008-12-19:34</id>
    <published>2008-12-19T12:01:00Z</published>
    <updated>2008-12-28T17:58:52Z</updated>
    <category term="Eventos"/>
    <category term="Startup"/>
    <category term="eventos"/>
    <category term="startup videos"/>
    <link href="http://www.agaelebe.com.br/2008/12/19/alguns-videos-do-resultson-day-2008" rel="alternate" type="text/html"/>
    <title>Alguns v&#237;deos do ResultsON Day 2008</title>
<content type="html">
            &lt;div class=&quot;center&quot;&gt;
&lt;img src=&quot;http://www.agaelebe.com.br/
assets/2008/12/19/resultsON_day_2008.JPG&quot; alt=&quot;Foto do evento ResultsON Day - O sucesso foi tão grande que tinha gente sentada no chão!&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;Ontem aconteceu no Espaço gafanhoto o &lt;a href=&quot;http://resultson.terra.com.br/blog/2008/12/18/muitas-ovelhas-negras-cabem-no-mesmo-lugar/&quot; title=&quot;ResultsON Day II&quot;&gt;ResultsON Day&lt;/a&gt; . Eu já venho me interessando pelo mundo dos startups por alguns anos. Tenho acompanhado a certa distância o mercado lá fora e também aqui no Brasil. Foi a primeira vez que fui em um Evento do gênero e, mesmo tendo perdido as três primeiras palestras, fiquei muito satisfeito com o resultado.&lt;/p&gt;

&lt;p&gt;Acredito que eventos como esse e o lançamento do &lt;a href=&quot;http://www.startupi.com.br&quot; title=&quot;Site do startupi&quot;&gt;Startupi&lt;/a&gt;  indicam que os startups da área de Internet e tecnologia no Brasil começam a florecer com maior força. Eu já havia me empolgado bastante com as palestras do Manoel Lemos do &lt;a href=&quot;http://www.blogblogs.com.br&quot;&gt;BlogBlogs&lt;/a&gt; / Brasigo e do Vínicius Teles do &lt;a href=&quot;Beonthe.net&quot;&gt;http://www.beonthe.net&lt;/a&gt;. Agora começo a conhecer quem são os Brasileiros por trás de alguns dos empreendimentos de maior sucesso da internet brasileira.&lt;/p&gt;

&lt;p&gt;Esse evento foi o primeiro em que pude filmar algumas das apresentações com a minha handcam que comprei com o dinheiro da venda do meu Nitendo Wii. É um modelo bem simples, para iniciantes, sem controles manuais, sem alta definição, mas com bastante espaço em disco e bastante compacta.  Acho que foi uma excelente troca. A qualidade dos vídeos produzidas não é muito boa, eu não tinha um bom posicionamento e muitas vezes meu braço se cansou.  :)&lt;/p&gt;

&lt;p&gt;O mais importante é que o som está audível e por isso acredito que meus vídeos possam ser úteis para os que não puderam comparecer no evento ou queiram rever algum trecho. Com certeza você escutará idéias e conselhos interessantes. Alguns dos slides usados nas apresentações &lt;a href=&quot;http://www.slideshare.net/rafaelbucco/slideshows&quot;&gt;foram colocados no slideshare&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Se você quer ver um resumo do evento com vídeo profissional e de alta qualidade veja &lt;a href=&quot;http://videolog.uol.com.br/video.php?id=395673&quot;&gt;este vídeo do KaduFilms no Videolog.tv&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Caso não consiga ver os vídeos colocados nesta página acesse minha conta no &lt;a href=&quot;http://agaelebe.blip.tv/&quot;&gt;Blip.tv&lt;/a&gt; e no &lt;a href=&quot;http://www.viddler.com/explore/agaelebe/&quot;&gt;Viddler&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;Alexsander Mandic&lt;/h2&gt;

&lt;p&gt;&amp;lt;embed src=&quot;http://blip.tv/play/AeHRVgA&quot; height=&quot;348&quot; width=&quot;437&quot;&gt;&amp;lt;/embed&gt;&lt;/p&gt;

&lt;h2&gt;Videolog.tv&lt;/h2&gt;

&lt;p&gt;&amp;lt;object height=&quot;348&quot; width=&quot;437&quot;&gt;&amp;lt;param /&gt;&amp;lt;param /&gt;&amp;lt;param /&gt;&amp;lt;embed src=&quot;http://www.viddler.com/simple/ecc32b41/&quot; height=&quot;348&quot; width=&quot;437&quot;&gt;&amp;lt;/embed&gt;&amp;lt;/object&gt;&lt;/p&gt;

&lt;h2&gt;pontoMobi&lt;/h2&gt;

&lt;p&gt;&amp;lt;embed src=&quot;http://blip.tv/play/AeHcegA&quot; height=&quot;348&quot; width=&quot;437&quot;&gt;&amp;lt;/embed&gt;&lt;/p&gt;

&lt;h2&gt;Beezzer - Empreender no Meio Da Crise&lt;/h2&gt;

&lt;p&gt;&amp;lt;object height=&quot;348&quot; width=&quot;437&quot;&gt;&amp;lt;param /&gt;&amp;lt;param /&gt;&amp;lt;param /&gt;&amp;lt;embed src=&quot;http://www.viddler.com/simple/8b67e46c/&quot; height=&quot;348&quot; width=&quot;437&quot;&gt;&amp;lt;/embed&gt;&amp;lt;/object&gt;&lt;/p&gt;

&lt;h2&gt;Sebrae&lt;/h2&gt;

&lt;p&gt;&amp;lt;embed src=&quot;http://blip.tv/play/AeHVaAA&quot; height=&quot;348&quot; width=&quot;437&quot;&gt;&amp;lt;/embed&gt;&lt;/p&gt;

&lt;h2&gt;Cietec&lt;/h2&gt;

&lt;p&gt;&amp;lt;embed src=&quot;http://blip.tv/play/AeHeNgA&quot; height=&quot;348&quot; width=&quot;437&quot;&gt;&amp;lt;/embed&gt;&lt;/p&gt;

&lt;h2&gt;Startupi&lt;/h2&gt;

&lt;p&gt;&amp;lt;embed src=&quot;http://blip.tv/play/AeOZEAA&quot; height=&quot;348&quot; width=&quot;437&quot;&gt;&amp;lt;/embed&gt;&lt;/p&gt;

&lt;h2&gt;Entrega das ovelhas para os Empreendedores do ano de 2008&lt;/h2&gt;

&lt;p&gt;&amp;lt;embed src=&quot;http://blip.tv/play/AeK9QgA&quot; height=&quot;348&quot; width=&quot;437&quot;&gt;&amp;lt;/embed&gt;&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.agaelebe.com.br/">
    <author>
      <name>agaelebe</name>
    </author>
    <id>tag:www.agaelebe.com.br,2008-12-06:29</id>
    <published>2008-12-06T21:02:00Z</published>
    <updated>2008-12-19T12:04:00Z</updated>
    <category term="Ruby"/>
    <category term="Tradu&#231;&#245;es"/>
    <category term="codigo"/>
    <category term="legibilidade"/>
    <category term="palestra"/>
    <link href="http://www.agaelebe.com.br/2008/12/6/deixando-seu-codigo-mais-legivel" rel="alternate" type="text/html"/>
    <title>Deixando seu c&#243;digo mais leg&#237;vel</title>
<content type="html">
            &lt;div class=&quot;center&quot;&gt;
&lt;img src=&quot;http://ecx.images-amazon.com/images/I/51n3w0lK9tL._BO2,204,203,200_PIsitb-sticker-arrow-click,TopRight,35,-76_AA240_SH20_OU01_.jpg&quot; alt=&quot;The non-designers design book&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;Finalmente saiu  a maioria dos &lt;a href=&quot;http://rubyconf2008.confreaks.com/&quot;&gt;vídeos da Rubyconf 2008&lt;/a&gt;. E tem muito material interessante. Como prometido, falarei um pouco da palestra de Micheal Granger. Achei a palestra razoável, algumas coisas um pouco óbvias e algumas dicas que eu não tinha conhecimento.&lt;/p&gt;

&lt;p&gt;Apresentarei aqui, resumidamente, as idéias passadas pelo palestrante.&lt;/p&gt;

&lt;p&gt;Você encontra Michael Granger no canal ruby-talk da freenode, seu apelido é &lt;strong&gt;ged&lt;/strong&gt;. Ele utiliza Ruby desde 2001 e esteve em 6 Rubyconfs desde então. Granger trabalha em um estúdio de animação em Portland chamado &lt;a href=&quot;http://www.laika.com/&quot;&gt;Laika&lt;/a&gt;. Ele participa ativamente de uma dezena de projetos open source como, por exemplo, o Bluecloth e criou o tema padrão do RDoc.&lt;/p&gt;

&lt;p&gt;A idéia de Granger é a de aplicar os príncipios do design visual para o código com objetivo de melhorar a comunicação deste com os seus leitores . O palestrante falou que evitaria entrar em questões polêmicas como, por exemplo, se é melhor utilizar dois ou quatro espaços para identar o código. Estes tipos de detalhes são escolhas pessoais que variam com o estilo do programador. O que ele apresentará são sugestões que nem sempre servirão para você mas em geral são válidas.&lt;/p&gt;

&lt;p&gt;Código é comunicação. É um conjunto de instruções para uma máquina. Mas é primariamente uma comunicação de idéias entre seres humanos. Estas pessoas, a audiência do código, são seus parceiros de trabalho, outras pessoas que irão alterar o código (no caso de um projeto open source)  ou aprender com ele e, em muitos casos, você mesmo, que terá que olhar para um código seu escrito a meses atrás para melhorá-lo, consertá-lo ou adicionar funcionalidades. É normal olharmos para o nosso próprio código e pensarmos, &#8220;Puxa, eu escrevi isso!?&#8221;&lt;/p&gt;

&lt;p&gt;Pa lermos o código de maneira eficiente precisamos maximizar o &#8220;fluxo&#8221;. O Fluxo, segundo Mihaly Csikszent,  é &#8220;a sensação de completude e foco energizante em uma atividade, com alto nível de prazer e satizfação&#8221;.  Existem alguns critérios para que o fluxo seja mantido:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;imersão completa no que faz;&lt;/li&gt;
&lt;li&gt;sabe o que tem que fazer a cada momento;&lt;/li&gt;
&lt;li&gt;tem um feedback rápido e preciso de quão bem você está fazendo;&lt;/li&gt;
&lt;li&gt;e um sentimento de que suas habilidades são desenvolvidas mas não são superadas pelas necessidades de ação.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Com pouco esforço podemos fazer mais para tornar nosso código mais legível e assim aumentar o fluxo. Por que não gostariámos de fazê-lo?&lt;/p&gt;

&lt;p&gt;Por misantropia, exagerando, por não gostarmos da humanidade. Alguns progamadores acreditam que ler código deve ser difícil, que nem todas as pessoas têm o direito de entender o que se passa. Ou por pânico em querer terminar o código o mais rápido possível. Porém a comunidade Ruby em geral não sofre destes dois problemas. O problema principal é a austeridade, isto é, um senso de simplicidade na aparência e estilo do código, já que a linguagem nos incentiva a escrever as coisas de maneira simplificada. Mas nem sempre devemos tomar este caminho.&lt;/p&gt;

&lt;p&gt;Então, o design adiciona estruturas e signficados para a comunicação usual. Granger pergunta: Sou um programador, o que eu sei sobre design visual? Ele nos introduz ao livro:  &lt;a href=&quot;http://www.amazon.com/Non-Designers-Design-Book-3rd-Designers/dp/0321534042/ref=pd_bxgy_b_img_b&quot; title=&quot;The non-designers design book&quot;&gt;&#8220;The non-designers design book&#8221;&lt;/a&gt; de Robin Williams, uma boa introdução para programadores sobre design que foi recomendado ao palestrante por um colega da área de usabilidade.&lt;/p&gt;

&lt;p&gt;Este livro apresenta os quatro príncipios básicos do design (a sigla &lt;strong&gt;CRAP&lt;/strong&gt;):&lt;/p&gt;

&lt;h1&gt;Contraste&lt;/h1&gt;

&lt;p&gt;Coisas que são diferentes devem parecer bastante diferentes. O mais importante numa página deve ser aquilo que chama a atenção do usuário na primeira vez em que ele olha para ela.&lt;/p&gt;

&lt;p&gt;Por convenção, já aplicamos várias regras para constraste:&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; Símbolos que são adicionados a variáveis ditinguem &lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; entre identificadores comuns e identficadores não usuais):&lt;/span&gt;
variavel_local
&lt;span class=&quot;Variable&quot;&gt;&lt;span class=&quot;Variable&quot;&gt;@&lt;/span&gt;variaveis_de_instancia&lt;/span&gt;
&lt;span class=&quot;Variable&quot;&gt;&lt;span class=&quot;Variable&quot;&gt;@@&lt;/span&gt;variaveis_de_classe&lt;/span&gt;
&lt;span class=&quot;Variable&quot;&gt;&lt;span class=&quot;Variable&quot;&gt;$&lt;/span&gt;globais&lt;/span&gt;

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; Constantes que na verdade são classes contra constantes &amp;quot;Puras&amp;quot;&lt;/span&gt;
&lt;span class=&quot;Variable&quot;&gt;BasickSocket&lt;/span&gt;
&lt;span class=&quot;Variable&quot;&gt;DEFAULT_DEPTH&lt;/span&gt;

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; Blocos de uma linha contra blocos de multiplas linhas&lt;/span&gt;
ary.&lt;span class=&quot;FunctionName&quot;&gt;map&lt;/span&gt; {|&lt;span class=&quot;Variable&quot;&gt;thing&lt;/span&gt;| thing.&lt;span class=&quot;FunctionName&quot;&gt;inspect&lt;/span&gt; }
ary.&lt;span class=&quot;FunctionName&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;do &lt;/span&gt;|&lt;span class=&quot;Variable&quot;&gt;thing&lt;/span&gt;|
  &lt;span class=&quot;Keyword&quot;&gt;next&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; thing.&lt;span class=&quot;FunctionName&quot;&gt;tainted?&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;||&lt;/span&gt; thing.&lt;span class=&quot;FunctionName&quot;&gt;imediate_object?&lt;/span&gt;
  list &lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; thing
&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Granger então dá algumas sugestões.&lt;/p&gt;

&lt;p&gt;Distinguirmos chamadas a métodos de variáveis locais.&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
filters.&lt;span class=&quot;FunctionName&quot;&gt;each&lt;/span&gt;{ |&lt;span class=&quot;Variable&quot;&gt;filter&lt;/span&gt;| ... }
&lt;/pre&gt;

&lt;p&gt;Neste código, filters é uma variável local ou uma chamada de método?
A distinção entre estes dois tipos pode ser facilmente obtida adicionando um &#8221;&lt;strong&gt;self.&lt;/strong&gt;&#8221; no caso
em que o parâmetro em questão é um método, mostrando que há uma chamada de método da classe em questão. O ponto indica que há uma mensagem sendo passada, portanto uma ação.&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
&lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;.&lt;span class=&quot;FunctionName&quot;&gt;filters&lt;/span&gt;.&lt;span class=&quot;FunctionName&quot;&gt;each&lt;/span&gt;{ |&lt;span class=&quot;Variable&quot;&gt;filter&lt;/span&gt;| ... }
&lt;/pre&gt;

&lt;p&gt;Olhando para o mesmo código não há ambiguidade. Não precisaremos procurar no código para saber o que é &#8220;filters&#8221; pois já sabemos imediatamente que é uma chamada de método.&lt;/p&gt;

&lt;p&gt;Outro exemplo são métodos de classe. Olhando para os métodos abaixo (parte do código do ActionController::Base do Rails) é difícil saber que eles são métodos de classe apenas olhando para esta parte do código.&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
  &lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;prepend_with_path&lt;/span&gt;(&lt;span class=&quot;FunctionArgument&quot;&gt; path &lt;/span&gt;)
    ...
    ...
    ...
  &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;append_view_path&lt;/span&gt;(&lt;span class=&quot;FunctionArgument&quot;&gt; path &lt;/span&gt;)
    ...
    ...
    ...
  &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Isto porque esta informação está 300 linhas acima:&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
  &lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Então você pode usar o estilo de declaração de método do singleton, empregando o operador de escopo (&lt;em&gt;*::&lt;/em&gt;*) e deixando mais claro que estes são métodos de classe e não métodos de instância nem apenas mensagens sendo passadas.&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
  &lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;self::prepend_with_path&lt;/span&gt;(&lt;span class=&quot;FunctionArgument&quot;&gt; path &lt;/span&gt;)
    ...
    ...
    ...
  &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;self::append_view_path&lt;/span&gt;(&lt;span class=&quot;FunctionArgument&quot;&gt; path &lt;/span&gt;)
    ...
    ...
    ...
  &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;h1&gt;Repetição&lt;/h1&gt;

&lt;p&gt;Coisas similares devem  permanecer parecidas. A consistência é um ponto chave.&lt;/p&gt;

&lt;p&gt;No código podemos alterar as relações espaciais e as espessuras das linhas.&lt;/p&gt;

&lt;p&gt;A primeira sugestão dada é a de se usar comentários para o auxílio na navegação.&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;

&lt;span class=&quot;Comment&quot;&gt;  &lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt;####################################&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;  &lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt;##  C L A S S   M E T H O D S&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;  &lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt;####################################&lt;/span&gt;

&lt;span class=&quot;Comment&quot;&gt;  &lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt;####################################&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;  &lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt;##  I N S T A N C E   M E T H O D S&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;  &lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt;####################################&lt;/span&gt;

&lt;/pre&gt;

&lt;p&gt;O uso destes blocos é interessante para marcar diferentes escopos dentro do código.&lt;/p&gt;

&lt;p&gt;Um segundo marcador menos óbvio e forte no código é usar marcadores para destacar modificadores de comportamento do código.&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;

&lt;span class=&quot;Comment&quot;&gt;  &lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt;#############&lt;/span&gt;
  funcao_de_modulo
&lt;span class=&quot;Comment&quot;&gt;  &lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt;#############&lt;/span&gt;

&lt;span class=&quot;Comment&quot;&gt;  &lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt;####&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;public&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;  &lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt;####&lt;/span&gt;

&lt;span class=&quot;Comment&quot;&gt;  &lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt;######&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;protected&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;  &lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt;######&lt;/span&gt;

&lt;span class=&quot;Comment&quot;&gt;  &lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt;####&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;private&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;  &lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt;####&lt;/span&gt;

&lt;/pre&gt;

&lt;p&gt;E o terceiro método é usar marcadores para delinear métodos. Assim, os códigos no alto dos métodos serão distinguidos do código dentro do método no Rdoc.&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt;## Method documentation&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;a_method&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;  &lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; comments of a trick bit of the method&lt;/span&gt;
  &lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;.&lt;span class=&quot;FunctionName&quot;&gt;some_trucky_stuff&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;h1&gt;Alinhamento&lt;/h1&gt;

&lt;p&gt;Coisas que tem alinhamento em seu propósito devem estar alinhadas visualmente. Os elementos não podem ser dispostos arbitrariamente.&lt;/p&gt;

&lt;p&gt;A maioria das pessoas já segue esse conselho em algum nível. É comum que usemos identação de código.  Existem outras coisas que você pode fazer, além de identar o código. Como, por exemplo, alinhar os operadores, para que fique mais fácil de se ler que um grupo de linhas está fazendo coisas similares (no exemplo aqui no blog não ficou perfeito já que essa fonte não é mono-espaçada).&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;initialize&lt;/span&gt;(&lt;span class=&quot;FunctionArgument&quot;&gt; name&lt;span class=&quot;FunctionArgument&quot;&gt;,&lt;/span&gt; description&lt;span class=&quot;FunctionArgument&quot;&gt;,&lt;/span&gt; host&lt;span class=&quot;FunctionArgument&quot;&gt;,&lt;/span&gt; port &lt;/span&gt;)
  &lt;span class=&quot;Variable&quot;&gt;&lt;span class=&quot;Variable&quot;&gt;@&lt;/span&gt;name&lt;/span&gt;             &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; name
  &lt;span class=&quot;Variable&quot;&gt;&lt;span class=&quot;Variable&quot;&gt;@&lt;/span&gt;description&lt;/span&gt;     &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; description
  &lt;span class=&quot;Variable&quot;&gt;&lt;span class=&quot;Variable&quot;&gt;@&lt;/span&gt;host&lt;/span&gt;              &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; host
  &lt;span class=&quot;Variable&quot;&gt;&lt;span class=&quot;Variable&quot;&gt;@&lt;/span&gt;port&lt;/span&gt;              &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; port
&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;E também alinhar cláusulas condicionais no final de uma linha:&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
seld.&lt;span class=&quot;FunctionName&quot;&gt;send_notification&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;.&lt;span class=&quot;FunctionName&quot;&gt;something_has_changed&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
                                  &lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;.&lt;span class=&quot;FunctionName&quot;&gt;user_wants_notification?&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
                                  &lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;.&lt;span class=&quot;FunctionName&quot;&gt;user_is_reachable?&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Ou métodos indivduais de uma longa cadeia de métodos:&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
 lines.&lt;span class=&quot;FunctionName&quot;&gt;collect&lt;/span&gt; {|&lt;span class=&quot;Variable&quot;&gt;str&lt;/span&gt;| str.&lt;span class=&quot;FunctionName&quot;&gt;chomp&lt;/span&gt; }.
       reject   {|&lt;span class=&quot;Variable&quot;&gt;str&lt;/span&gt;| str &lt;span class=&quot;Keyword&quot;&gt;=~&lt;/span&gt;&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;String&quot;&gt;^&lt;span class=&quot;UserDefinedConstant&quot;&gt;\s&lt;/span&gt;*&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;(&lt;/span&gt;$.+&lt;span class=&quot;String&quot;&gt;)&lt;/span&gt;&lt;/span&gt;$&lt;/span&gt;&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;/&lt;/span&gt;&lt;/span&gt; }.
       collect  {|&lt;span class=&quot;Variable&quot;&gt;str&lt;/span&gt;| str.&lt;span class=&quot;FunctionName&quot;&gt;scan&lt;/span&gt;(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;\w&lt;/span&gt;+&lt;/span&gt;&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;/&lt;/span&gt;&lt;/span&gt;) }.
       flatten.
       uniq

&lt;/pre&gt;

&lt;p&gt;Outra boa prática é adicionar espaço aos seus parênteses (colchetes e chaves para o casso de arrays e hases)  para tornar mais fácil a visualização dos argumentos.&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;initialize&lt;/span&gt;(&lt;span class=&quot;FunctionArgument&quot;&gt; name&lt;span class=&quot;FunctionArgument&quot;&gt;,&lt;/span&gt; description &lt;/span&gt;)
...
&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;

servers &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; [  [&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;localhost&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;Number&quot;&gt;1414&lt;/span&gt;], [&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;staging&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;Number&quot;&gt;2014&lt;/span&gt;]  ]
&lt;/pre&gt;

&lt;h1&gt;Proximidade&lt;/h1&gt;

&lt;p&gt;Coisas relacionadas devem ser agrupadas. &lt;/p&gt;

&lt;p&gt;Michael acredita que esse é o mais importante dos príncipios. Ele diz que um exemplo básico disso é a organização de seus arquivos. É interessante também o uso de espaçamento vertical (linhas em branco) para separar partes do código que se relacionam para que esta relação fique clara visualmente. Métodos como vários argumentos não devem ter os parênteses omitidos, isso dificulta a letura.&lt;/p&gt;

&lt;p&gt;Concluindo, Granger nos reitera que código é comunicação e que devemos aprender com os designers para que possamos escrever código mais legível e assim economizar tempo no futuro, quando nós mesmos ou outras pessoas lerão nosso código.&lt;/p&gt;

&lt;p&gt;Depois dessa palesta, já vi que tenho muitas linhas de código a serem editadas. Se tiverem sugestões de como escrever um código mais legível, não deixem de comentar.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.agaelebe.com.br/">
    <author>
      <name>agaelebe</name>
    </author>
    <id>tag:www.agaelebe.com.br,2008-11-07:23</id>
    <published>2008-11-07T17:15:00Z</published>
    <updated>2008-11-07T17:16:53Z</updated>
    <category term="Ruby"/>
    <link href="http://www.agaelebe.com.br/2008/11/7/o-que-faz-um-codigo-belo" rel="alternate" type="text/html"/>
    <title>O que torna um c&#243;digo belo?</title>
<content type="html">
            &lt;p&gt;&lt;img title=&quot;Flor&quot; src=&quot;http://www.agaelebe.com.br/assets/2008/11/4/bela_flor.jpg&quot; alt=&quot;Uma flor, por mim&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Nesta semana está acontecendo a Rubyconf 2008 e  &lt;a href=&quot;http://rubyconf.org/talks/65&quot; title=&quot;Making Your Code CRAPpier: Applying Principles of Visual Design To Code &quot;&gt;uma das palestras que me chamou a atenção é a de Michael Granger&lt;/a&gt; que tratará sobre como deixar seu código Ruby mais legível, comunicativo e mais fácil de se manter. Para tal ele irá aplicar o príncipio de design visual de Robin Williams conhecido como CRAP (sigla para Contraste, Repetição, Alinhamento e Proximidade). Para quem não entende inglês, o significado da palava &#8220;crap&#8221; é lixo, porcaria. Além disso ele usará algumas idéias do método de programação espartano (Spartan Programming), Michael Schwern, Marcel Molina Jr. e do grande mestre dos computeiros, Donald Knuth.&lt;/p&gt;

&lt;p&gt;Pois, justamente, semana passada assisti uma das palestras da Rubyconf 2007 no site da Confreaks (espero que as palestras da Rubyconf 2008 também estejam lá). Era a &lt;a href=&quot;http://rubyconf2007.confreaks.com/d1t1p1_what_makes_code_beautiful.html&quot; title=&quot;What Makes Code Beautiful?&quot;&gt;palestra de Marcel Molina Jr.&lt;/a&gt; e ele falava sobre o que faz um código belo. Esta palestra também foi uma &lt;a href=&quot;http://rubyhoedown2007.confreaks.com/session09.html&quot; title=&quot;Keynote Address: What makes code beautiful?&quot;&gt;keynote na Ruby Hoedown 2007&lt;/a&gt;. Tentarei apresentar aqui sua essência.&lt;/p&gt;

&lt;p&gt;Marcel disse que não faria uma apresentação acadêmica.  Afirmou que, ao pensamos em beleza, geralmente pensamos em aparência e nos vem a imagem de um bebê, uma mulher ou uma flor. Mas essa definição é muito superficial.&lt;/p&gt;

&lt;p&gt;Software belo é a mesma coisa que um bom software. Como já dizia o pensador francês Jean-Jacques Rousseau. &#8220;Bom nada mais é que a beleza em ação e ambos tem uma fonte comum na &lt;em&gt;natureza organizada&lt;/em&gt;&#8221;.&lt;/p&gt;

&lt;p&gt;O conceito de natureza organizada é explicado por Pitágoras, que conhecemos no segundo grau, nas aulas de geometria. Ele dizia que a beleza vem dos números, eles estão em toda a parte. &#8220;Todas as coisas existem por serem ordenadas. E elas são ordenadas porque são a &lt;em&gt;realização de leis matemáticas&lt;/em&gt;&#8221;. Pitágoras ouviu a beleza de som que vinha dos martelos de um ferreiro, uma verdadeira melodia. Então observou que existia uma proporção entre os diferentes tamanhos de martelo. Este conceito de proporcionalidade também foi usado nas construções arquitetônicas da  Grécia antiga.&lt;/p&gt;

&lt;p&gt;Contudo foi a definição de São Tomas de Aquino aquela que o palestrante explorou com maior profundidade e que ele acredita que melhor se encaixa com software. Para o sábio teólogo a beleza é definida por três regras:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;a proporção&lt;/em&gt;, isto é, apresentar uma boa estrutura em que a relação de tamanho entre as diferentes partes do objeto seja proporcional, mantendo o tamanho o menor possível.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;a &lt;em&gt;integridade&lt;/em&gt;, isto é, o objeto deve servir para o propósito em questão. Ele exemplifica falando do martelo de cristal: tem beleza física, mas não tem integridade pois não é uma boa solução para o problema de bater pregos, já que se quebraria em diversos partes se fosse usado para tal propósito.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;a &lt;em&gt;clareza&lt;/em&gt;, isto é, o objeto deve ser simples/claro. Vide os designs desenvolvidos pela Apple.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Em seguida, Marcel dá um exemplo para mostrar como estes três conceitos se aplicam a código. 
O programa usado como exemplo deve converter strings de um arquivo XML para tipos correspondentes (fazer a coerção) em Ruby:&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;true&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;      =&amp;gt;  &lt;span class=&quot;BuiltInConstant&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;false&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;     =&amp;gt;  &lt;span class=&quot;BuiltInConstant&quot;&gt;false&lt;/span&gt;
&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;42&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;        =&amp;gt;  &lt;span class=&quot;Number&quot;&gt;42&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Ele então chegou a seguinte implementação:&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;TypeName&quot;&gt;CoercibleString&lt;span class=&quot;InheritedClass&quot;&gt; &lt;span class=&quot;InheritedClass&quot;&gt;&amp;lt;&lt;/span&gt; String&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;attr_accessor&lt;/span&gt; &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;generator&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;coerce&lt;/span&gt;
    attempt &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;BuiltInConstant&quot;&gt;nil&lt;/span&gt;
    &lt;span class=&quot;Keyword&quot;&gt;break&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;unless&lt;/span&gt; (attemp &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; coercions.&lt;span class=&quot;FunctionName&quot;&gt;next&lt;/span&gt;).&lt;span class=&quot;FunctionName&quot;&gt;nil?&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;while&lt;/span&gt; coercions.&lt;span class=&quot;FunctionName&quot;&gt;next?&lt;/span&gt;
    attempt.&lt;span class=&quot;FunctionName&quot;&gt;nil?&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt; : attempt
  &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;Keyword&quot;&gt;private&lt;/span&gt;
    &lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;coercions&lt;/span&gt;
      &lt;span class=&quot;LibraryClassType&quot;&gt;Generator&lt;/span&gt;.&lt;span class=&quot;FunctionName&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;do &lt;/span&gt;|&lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;.&lt;span class=&quot;Variable&quot;&gt;generator&lt;/span&gt;|
        try { &lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;  &lt;span class=&quot;Keyword&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;true&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;&lt;/span&gt;         }
        try { [&lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;false&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;BuiltInConstant&quot;&gt;false&lt;/span&gt;]}
        try { &lt;span class=&quot;Variable&quot;&gt;Integer&lt;/span&gt;(&lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;)           }
        try { &lt;span class=&quot;LibraryClassType&quot;&gt;Date&lt;/span&gt;.&lt;span class=&quot;FunctionName&quot;&gt;parse&lt;/span&gt;(&lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;)        }
       &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;try&lt;/span&gt;
      attempt, desired &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;yield&lt;/span&gt;
      generator.&lt;span class=&quot;FunctionName&quot;&gt;yield&lt;/span&gt;(desired.&lt;span class=&quot;FunctionName&quot;&gt;nil?&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;?&lt;/span&gt; attempt : desired) &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; attempt
      &lt;span class=&quot;Keyword&quot;&gt;rescue&lt;/span&gt; &lt;span class=&quot;Variable&quot;&gt;ArgumentError&lt;/span&gt;
        generator.&lt;span class=&quot;FunctionName&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;BuiltInConstant&quot;&gt;nil&lt;/span&gt;
      &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Ele mostra também a implementação final do programa:&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
&lt;span class=&quot;Variable&quot;&gt;Class&lt;/span&gt; &lt;span class=&quot;Variable&quot;&gt;String&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;self.coerce&lt;/span&gt;(&lt;span class=&quot;FunctionArgument&quot;&gt;string&lt;/span&gt;)
    &lt;span class=&quot;Keyword&quot;&gt;case&lt;/span&gt; string
    &lt;span class=&quot;Keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;true&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;&lt;/span&gt; :          &lt;span class=&quot;BuiltInConstant&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;Keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;false&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;&lt;/span&gt; :         &lt;span class=&quot;BuiltInConstant&quot;&gt;false&lt;/span&gt;
    &lt;span class=&quot;Keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;String&quot;&gt;^&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;[&lt;/span&gt;1-9&lt;span class=&quot;String&quot;&gt;]&lt;/span&gt;&lt;/span&gt;+&lt;span class=&quot;UserDefinedConstant&quot;&gt;\d&lt;/span&gt;*$&lt;/span&gt;&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;/&lt;/span&gt;&lt;/span&gt; :   &lt;span class=&quot;Variable&quot;&gt;Integer&lt;/span&gt;(string)
    &lt;span class=&quot;Keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;Variable&quot;&gt;DATETIME_FORMAT&lt;/span&gt;:  &lt;span class=&quot;LibraryClassType&quot;&gt;Time&lt;/span&gt;.&lt;span class=&quot;FunctionName&quot;&gt;parse&lt;/span&gt;(string)
    &lt;span class=&quot;Keyword&quot;&gt;else&lt;/span&gt;
      string
    &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Marcel explica brevemente o funcionamento da solução e então avalia a beleza da primeira implementação.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Proporcionalidade: em relação as partes do código (métodos) são mais ou menos proporcionais. Porém, se formos olhar a quantidade de código, é realmente necessário tanto código para resolver o problema? A segunda solução tem metade do tamanho, portanto a proporcionalidade da primeira solução é bem ruim.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Integridade: No Ruby 1.9 os &lt;em&gt;generators&lt;/em&gt; (usados pela primeira solução) são implementados com &lt;em&gt;threads&lt;/em&gt;, mas no Ruby 1.8 eles usam &lt;em&gt;continuations&lt;/em&gt;, o que é bastante lento. Mudando para a segunda implementação os testes de Marcel rodaram uma ordem de magnitude mais rápidos em relação a primeira. Ou seja, falhamos  também na integridade.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Claridade: Marcel diz que teve que explicar o funcionamento do primeiro código e diz saber que ele não é claro. Já o segundo é bem mais claro (alguém tem dúvidas disso?).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Inicialmente, ele não sabia que o código era ruim. Marcel pensou que poderia ser um jeito novo, interessante de se resolver o problema de coerção. Mas, no final das contas, mostrou-se não ser um belo código.&lt;/p&gt;

&lt;p&gt;Então ele afirma: &lt;em&gt;Você não escolhe um ou dois princípios. Os três são necessários e nenhum deles é suficiente.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Por exemplo, não se deve sacrificar a clareza em prol da proporcionalidade, isto é, criar códigos curtos que são incompreensíveis.&lt;/p&gt;

&lt;p&gt;Você pode me explicar  o que fazem os códigos a seguir? Bem, deixa pra lá.&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
&lt;span class=&quot;FunctionName&quot;&gt;expand&lt;/span&gt;(&lt;span class=&quot;FunctionName&quot;&gt;join&lt;/span&gt;(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,(map { &lt;span class=&quot;Keyword&quot;&gt;/&lt;/span&gt;\s&lt;span class=&quot;Keyword&quot;&gt;+&lt;/span&gt;\z&lt;span class=&quot;Keyword&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;?&lt;/span&gt; ( &lt;span class=&quot;Variable&quot;&gt;&lt;span class=&quot;Variable&quot;&gt;$&lt;/span&gt;_&lt;/span&gt; ) : (&lt;span class=&quot;Variable&quot;&gt;&lt;span class=&quot;Variable&quot;&gt;$&lt;/span&gt;_&lt;/span&gt;, &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;&lt;/span&gt;) } &lt;span class=&quot;Variable&quot;&gt;&lt;span class=&quot;Variable&quot;&gt;@&lt;/span&gt;t&lt;/span&gt;), &lt;span class=&quot;Variable&quot;&gt;&lt;span class=&quot;Variable&quot;&gt;$&lt;/span&gt;tail&lt;/span&gt;));

foreach (&lt;span class=&quot;Variable&quot;&gt;&lt;span class=&quot;Variable&quot;&gt;@&lt;/span&gt;ARGV&lt;/span&gt;) {
 &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;\.&lt;/span&gt;&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;[&lt;/span&gt;^.&lt;span class=&quot;String&quot;&gt;]&lt;/span&gt;&lt;/span&gt;+&lt;span class=&quot;String&quot;&gt;)&lt;/span&gt;&lt;/span&gt;$&lt;/span&gt;&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;/&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;Variable&quot;&gt;&lt;span class=&quot;Variable&quot;&gt;$&lt;/span&gt;exten&lt;/span&gt;{&lt;span class=&quot;Variable&quot;&gt;&lt;span class=&quot;Variable&quot;&gt;$&lt;/span&gt;1&lt;/span&gt;}&lt;span class=&quot;Keyword&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;+&lt;/span&gt; foreach glob &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;$_/*.*&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
}
&lt;/pre&gt;

&lt;p&gt;O palestrante então nos introduz ao livro &lt;em&gt;Smalltalk Best Practices Patterns&lt;/em&gt; de Kent Beck (sim, o mesmo cara por trás do XP).
Neste livro dos anos 80, o autor trabalha com a linguagem Smalltalk e dá algumas dicas de como desenvolver software de melhor qualidade;&lt;/p&gt;

&lt;p&gt;Ele então cita algumas frases do livro:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&#8220;Este padrão enfatiza a &lt;em&gt;legibilidade&lt;/em&gt;.&#8221;&lt;/li&gt;
&lt;li&gt;&#8220;Métodos de uma linha estão lá para &lt;em&gt;comunicar-se&lt;/em&gt;.&#8221;&lt;/li&gt;
&lt;li&gt;&#8220;Objetos são mais fáceis de se gerenciar se são &lt;em&gt;divididos em pequenas partes&lt;/em&gt;.&#8221;&lt;/li&gt;
&lt;li&gt;&#8220;A maioria dos bons métodos escritos em Smalltalk cabem em umas poucas linhas.&#8221;&lt;/li&gt;
&lt;li&gt;&#8220;Você não &lt;em&gt;gasta três ou quatro linhas&lt;/em&gt; para expressar iteração, você &lt;em&gt;gasta uma palavra.&lt;/em&gt;&#8221;&lt;/li&gt;
&lt;li&gt;&#8220;O problema de um código como este é que &lt;em&gt;você não pode lê-lo e entender o que se passa&lt;/em&gt;&#8221;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;E estas frases nada mais fazem que afirmar os três conceitos de beleza de São Tomás de Aquino.&lt;/p&gt;

&lt;p&gt;Marcel nos pergunta, como tudo isso dito aqui é útil?&lt;/p&gt;

&lt;p&gt;Bem, o código da segunda implementação que taxamos como belo não tem nada de especial.
Mas, a 40 anos atrás isso era fantástico, inovador. Imagine trabalhar com assembly e ter a funcionalidade do switch (case). Mas agora, Ruby é o jeito mais belo de se escrever software nos últimos 20 anos embora ele pareça simples. É um alvo em movimento.&lt;/p&gt;

&lt;p&gt;John McCarthy, o criador da linguagem Lisp (ele apenas especificou a linguagem, não a implementou) introduziu o conceito de &lt;em&gt;if_&#8221; na programação. Você consegue imaginar programação sem o _if&lt;/em&gt;? As pessoas trabalhavam sem ele. Mas, quando introduzido, o _if_ deve ter sido um belo conceito.&lt;/p&gt;

&lt;p&gt;E aqui vai uma frase interessante de Niels Bohr. &#8220;Um especialista é uma pessoa que cometeu todos erros que poderia ter feito num campo bem restrito&#8221;. &lt;/p&gt;

&lt;p&gt;Assim Marcel fala que sua implementação inicial de coerção foi um erro. Assim como, quem inicialmente introduziu o &lt;em&gt;switch&lt;/em&gt; poderia ter optado por uma implementação padrão na época.&lt;/p&gt;

&lt;p&gt;Mas ele tentava fazer algo diferente que fosse melhor. E no final, em relação a beleza, o código era ruim.&lt;/p&gt;

&lt;p&gt;Ruby é otimizada para beleza. O que Marcel tenta chegar com isso é, que quando trabalhando com software:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;tente imaginar melhores modos de expressão&lt;/li&gt;
&lt;li&gt;violações das três regras da beleza revelam erros - se você perceber que está violando as regras
tente fazer ajustes ou reescreva o código&lt;/li&gt;
&lt;li&gt;se você fizer isto suficientemente você pode terminar por  obter algo inovador e belo&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Esta é uma simples abordagem que Marcel tem usado e que ele acredita que tem sido um sucesso devido ao bom retorno que tem recebido.
O palestrante finaliza agradecendo ao Matz e ao Ruby Core Team por terem criado Ruby, que, na sua opinião, é a linguagem de programação mais bela em uso.&lt;/p&gt;

&lt;p&gt;Espero que este texto tenha sido útil, apesar de eu ter violado as regras de beleza!&lt;/p&gt;

&lt;p&gt;Assim que eu tiver alguma informação da palestra de Michael Granger na Rubyconf 2008, tratarei sobre ela aqui.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.agaelebe.com.br/">
    <author>
      <name>agaelebe</name>
    </author>
    <id>tag:www.agaelebe.com.br,2008-10-10:16</id>
    <published>2008-10-10T22:54:00Z</published>
    <updated>2008-11-08T22:26:59Z</updated>
    <category term="Ruby"/>
    <category term="Tradu&#231;&#245;es"/>
    <category term="ia"/>
    <category term="paipr"/>
    <link href="http://www.agaelebe.com.br/2008/10/10/traducao-paradigmas-da-programao-para-inteligencia-artificial" rel="alternate" type="text/html"/>
    <title>Tradu&#231;&#227;o: Paradigmas da Programa&#231;&#227;o para Intelig&#234;ncia Artificial - introdu&#231;&#227;o e parte 1</title>
<content type="html">
            &lt;p&gt;Este artigo é uma tradução do &lt;a href=&quot;http://olabini.com/blog/2008/09/paradigms-of-artificial-intelligence-programming-in-ruby/&quot; title=&quot;Paradigms of Artificial Intelligence Programming (in Ruby)&quot;&gt;artigo original de Ola Bini&lt;/a&gt;. Agradeço ao autor por permitir que eu realizasse tradução de seus artigos desta série. Sintan-se livres para apontar erros e sugestões para melhorias na tradução.&lt;/p&gt;

&lt;p&gt;Acho que se você se interessa por Ruby, deve saber quem é Ola Bini. Se não conhece, recomendo que leia a &lt;a href=&quot;http://www.akitaonrails.com/2007/06/21/conversando-com-ola-bini-jruby-core-team-member&quot; title=&quot;Conversando com Ola Bini&quot;&gt;entrevista feita pelo Akita&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Eu tenho estudado algumas coisas ligadas a IA (Inteligência Artificial), especialmente aprendizado de máquina (Machine Learning - ML). Pretendo escrever aqui alguns artigos de ML no futuro. Enquanto isso vou começar com esta tradução, já que achei a série de artigos do Ola bastante interessante. O código dele também é muito bem escrito.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2&gt;Paradigmas da Programação para Inteligência Artificial (em Ruby)&lt;/h2&gt;

&lt;p&gt;Já que eu não me canso de participar de diferentes projetos, decidi inciar algo em que pensei a começar faz um bom tempo. Existem algumas razões para fazê-lo, a principal entre elas é que eu queria voltar a brincar com IA, e eu queria ter um projeto com muitas peçinhas que eu possa construir quando tenho algum tempo livre. Se, ao mesmo tempo, o projeto acabar por se tornar educacional ou útil para outras pessoas, bem, não estou reclamando!&lt;/p&gt;

&lt;p&gt;Então, o quê é?&lt;/p&gt;

&lt;p&gt;Bem, primeiro eu gostaria de apresentar um livro. Ele se chama &lt;a href=&quot;http://norvig.com/paip.html&quot; title=&quot;Paradigms of Artificial Intelligence Programming&quot;&gt;Paradigms of Artificial Intelligence Programming&lt;/a&gt; ou, de maneira mais curta, PAIP. Foi escrito por &lt;a href=&quot;http://norvig.com&quot;&gt;Peter Norvig&lt;/a&gt;, que também escrevel alguns outros livros sobre IA. Atualmente ele é diretor de pesquisa no Google. O PAIP é provalmente meu livro preferido de IA, e também meu livro favorito de Common Lisp. É realmente um livro excelente. De verdade. Se você tem algum interesse em um destes dois assuntos você deve adquirí-lo. O PAIP não cobre assuntos de ponta da IA. Ao invés disso ele usa a visão histórica e analisa diversos exemplos de épocas diferentes, indo dos primeiros programas até coisas bastante avançadas.&lt;/p&gt;

&lt;p&gt;Eu o li inúmeras vezes, examinei o código, refinei-o e assim por diante. É muito divertido. Mas isso foi faz alguns anos. Então, basicamente, o que quero fazer é explorar o livro de novo. Mas desta vez escreverei todos os programas em Ruby - convertendo-os do Common Lisp e então talvez melhorando-os um pouco para fazê-los mais idiomáticos. E planejo colocar aqui. Ou melhor, vou colocar o código fonte em &lt;a href=&quot;http://www.github.com/olabini/paipr&quot;&gt;http://www.github.com/olabini/paipr&lt;/a&gt;.
Irei blogar sobre o código que escrever. Você não tem necessariamente que possuir o livre, já que eu irei cercar o código com algumas descrições e explicações.&lt;/p&gt;

&lt;p&gt;Mais uma vez, então, por que alguém deveria se importar? Bem, não sei. Talvez ninguém ligue. Mas para mim, pessoalmente, será uma experiência interessante converter Common Lisp idiomático para Ruby idiomático. Será divertido revisitar as antigas abordagens da IA. E poderá servir como uma boa introdução, com bastante código, ao assunto para qualquer um que se interesse por ele.&lt;/p&gt;

&lt;p&gt;Eu tenho a permissão de Peter Norvig para fazer isto. O código Ruby que estou escrevendo é coberto pela licença MIT, enquanto qualquer código Lisp colocada como parte deste exercício é coberto por esta licença: &lt;a href=&quot;http://norvig.com/license.html&quot;&gt;http://norvig.com/license.html&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Também atente-se ao fato que nem sempre escreverei o código Ruby mais óbvio - Será bom que ele tenha algumas conexões com código Lisp original.&lt;/p&gt;

&lt;hr /&gt;

&lt;h1&gt;Parte 1 - Geração de Linguagem&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;http://olabini.com/blog/2008/09/language-generation/&quot; title=&quot;Language generation&quot;&gt;Artigo original de Ola Bini&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Este artigo é o primeiro da série de artigos sobre o PAIPr. Leia a introdução acima para entender mais sobre o conceito.&lt;/p&gt;

&lt;p&gt;Hoje eu gostaria de começar olhando o Capítulo 2. Você pode encontrar o código em lib/ch02 no repositório.&lt;/p&gt;

&lt;p&gt;O Capítulo 2 introduz o Common Lisp através da criação de uma séria de maneiras de se fazer a geração de sentenças em inglês, baseando-se em simples gramáticas. É um capítulo interessante para se começar, visto que o código é simples e então é simples comparar as versões em Ruby e Common Lisp.&lt;/p&gt;

&lt;p&gt;A primeira parte que temos que considerar é o arquivo &lt;em&gt;common.rb&lt;/em&gt;, que contém dois métodos que precisaremos mais tarde:&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;pp&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;one_of&lt;/span&gt;(&lt;span class=&quot;FunctionArgument&quot;&gt;set&lt;/span&gt;)
  [set.&lt;span class=&quot;FunctionName&quot;&gt;random_elt&lt;/span&gt;]
&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;TypeName&quot;&gt;Array&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;random_elt&lt;/span&gt;
    &lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;[&lt;span class=&quot;FunctionName&quot;&gt;rand&lt;/span&gt;(&lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;.&lt;span class=&quot;FunctionName&quot;&gt;length&lt;/span&gt;)]
  &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Como você pode ver eu também requeri o pp, para facilitar a a impressão de estruturas posteriormente.&lt;/p&gt;

&lt;p&gt;Ambos os métodos one&lt;em&gt;of  (um de) e e random&lt;/em&gt;elt (elemento aleatório)  são métodos extremamente simples, mas é sempre legal ter este tipo de abstração. Estou mantendo a mesma nomenclatura do livro para estes dois métodos.&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;common&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;sentence&lt;/span&gt;; noun_phrase &lt;span class=&quot;Keyword&quot;&gt;+&lt;/span&gt; verb_phrase; &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;noun_phrase&lt;/span&gt;; article &lt;span class=&quot;Keyword&quot;&gt;+&lt;/span&gt; noun; &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;verb_phrase&lt;/span&gt;; verb &lt;span class=&quot;Keyword&quot;&gt;+&lt;/span&gt; noun_phrase; &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;article&lt;/span&gt;; one_of &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;%w(&lt;/span&gt;the a&lt;span class=&quot;String&quot;&gt;)&lt;/span&gt;&lt;/span&gt;; &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;noun&lt;/span&gt;; one_of &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;%w(&lt;/span&gt;man ball woman table&lt;span class=&quot;String&quot;&gt;)&lt;/span&gt;&lt;/span&gt;; &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;verb&lt;/span&gt;; one_of &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;%w(&lt;/span&gt;hit took saw liked&lt;span class=&quot;String&quot;&gt;)&lt;/span&gt;&lt;/span&gt;; &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Como você pode ver, todos os métodos apenas definem sua estrutura combinando o resultado de métodos mais básicos. Uma  frase substantiva (noun_phrase) é formada por um artigo (article) e então um substantivo (noun). Um artigo é &#8216;o/a&#8217; (the) ou &#8216;um/uma&#8217; (a) e um substantivo pode ser &#8216;homem&#8217; (man). &#8216;bola&#8217; (ball), &#8216;mulher&#8217; (women) ou &#8216;mesa&#8217; (table). Se você executar a sentença algumas vezes verá que em algumas ocasiões irá obter sentenças perfeitamente plausíveis como [&#8220;uma&#8221; &#8220;bola&#8221;,&#8221;acertou&#8221;,&#8221;a&#8221;,&#8221;mesa&#8221; ]. Mas você também pode obter coisas menos interessantes, como [&#8220;uma&#8221;,&#8221;bola&#8221;,&#8221;acertou&#8221;,&#8221;uma&#8221;,&#8221;bola&#8221;]. Neste ponto o espaço para variação é bastante limitado, mesmo assim você pode notar que há uma versão simplificada da língua inglesa nestes métodos.&lt;/p&gt;

&lt;p&gt;Para criar um exemplo que envolve algumas estruturas mais interessantes, podemos introduzir adjetivos (adjectives) e preposições (prepositions). Dado que estes podem se repetir zero ou muitas vezes, nós iremos usar uma produção chamada PP* e Adj* (pp&lt;em&gt;star e adj&lt;/em&gt;star no código). Isto está no &lt;em&gt;simple2.rb&lt;/em&gt;:&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;simple&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;adj_star&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; [] &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;rand&lt;/span&gt;(&lt;span class=&quot;Number&quot;&gt;2&lt;/span&gt;) &lt;span class=&quot;Keyword&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;Number&quot;&gt;0&lt;/span&gt;
  adj &lt;span class=&quot;Keyword&quot;&gt;+&lt;/span&gt; adj_star
&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;pp_star&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; [] &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;rand&lt;/span&gt;(&lt;span class=&quot;Number&quot;&gt;2&lt;/span&gt;) &lt;span class=&quot;Keyword&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;Number&quot;&gt;0&lt;/span&gt;
  pp &lt;span class=&quot;Keyword&quot;&gt;+&lt;/span&gt; pp_star
&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;noun_phrase&lt;/span&gt;; article &lt;span class=&quot;Keyword&quot;&gt;+&lt;/span&gt; adj_star &lt;span class=&quot;Keyword&quot;&gt;+&lt;/span&gt; noun &lt;span class=&quot;Keyword&quot;&gt;+&lt;/span&gt; pp_star; &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;pp&lt;/span&gt;; prep &lt;span class=&quot;Keyword&quot;&gt;+&lt;/span&gt; noun_phrase; &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;adj&lt;/span&gt;; one_of &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;%w(&lt;/span&gt;big little blue green adiabatic&lt;span class=&quot;String&quot;&gt;)&lt;/span&gt;&lt;/span&gt;; &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;prep&lt;/span&gt;; one_of &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;%w(&lt;/span&gt;to in by with on&lt;span class=&quot;String&quot;&gt;)&lt;/span&gt;&lt;/span&gt;; &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Nada muda muito aqui, exceto que em ambas produções opcionais retornamos aleatoriamente um array vazio em 50% do tempo. E então eles podem se chamar recursivamente. A produção de frases substantivas também muda um pouco, e adj e prep nos dão os dois novos terminais necessários. Se você tentar usar deste modo, poderá obter alguns resultados ainda mais interessantes, como por exemplo: [&#8220;uma&#8221;, &#8220;mesa&#8221;, &#8220;pegou&#8221;, &#8220;um&#8221;, &#8220;grande&#8221;, &#8220;adiabático&#8221;, &#8220;homem&#8221;]. É claro que ainda permanece sem sentido. E parece que essa abordagem com aleatoriedade gerará algumas saídas bem grandes em alguns casos. Para fazer esta solução realmente boa é provável que tenhamos que incluir algum viés redutor nos adjetivos e preposições baseado no tamanho da string já gerada.&lt;/p&gt;

&lt;p&gt;Outro problema com esta abordagem é que ela é meio incômoda. Usar métodos para a gramática provavelmente não é  uma boa escolha a longo prazo. Mais especificamente, nós ficamos atados a esta implementação tendo a gramática sendo representada por métodos.&lt;/p&gt;

&lt;p&gt;Uma alternativa viável é representar tudo como uma definição de gramática - usando uma solução baseada em regras. A primeira parte do arquivo &lt;em&gt;rule_based.rb&lt;/em&gt; se parece com isto:&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;common&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; Uma gramática para um subconjunto trivial da língua inglesa&lt;/span&gt;
&lt;span class=&quot;Variable&quot;&gt;&lt;span class=&quot;Variable&quot;&gt;$&lt;/span&gt;simple_grammar&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; {
  &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;sentence&lt;/span&gt; =&amp;gt; [[&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;noun_phrase&lt;/span&gt;, &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;verb_phrase&lt;/span&gt;]],
  &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;noun_phrase&lt;/span&gt; =&amp;gt; [[&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;Article&lt;/span&gt;, &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;Noun&lt;/span&gt;]],
  &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;verb_phrase&lt;/span&gt; =&amp;gt; [[&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;Verb&lt;/span&gt;, &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;noun_phrase&lt;/span&gt;]],
  &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;Article&lt;/span&gt; =&amp;gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;%w(&lt;/span&gt;the a&lt;span class=&quot;String&quot;&gt;)&lt;/span&gt;&lt;/span&gt;,
  &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;Noun&lt;/span&gt; =&amp;gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;%w(&lt;/span&gt;man ball woman table&lt;span class=&quot;String&quot;&gt;)&lt;/span&gt;&lt;/span&gt;,
  &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;Verb&lt;/span&gt; =&amp;gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;%w(&lt;/span&gt;hit took saw liked&lt;span class=&quot;String&quot;&gt;)&lt;/span&gt;&lt;/span&gt;}

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; A gramática usada pelo gerador. Inicialmente ela é $simple_grammar, mas&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; podemos mudar para outras gramáticas&lt;/span&gt;
&lt;span class=&quot;Variable&quot;&gt;&lt;span class=&quot;Variable&quot;&gt;$&lt;/span&gt;grammar&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;Variable&quot;&gt;&lt;span class=&quot;Variable&quot;&gt;$&lt;/span&gt;simple_grammar&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Note que estou usando arrays duplos para as produções que não são terminais. Existe uma razão para isso que ficará mais clara mais tarde com as gramáticas que se baseiam nisto. Neste instante, entretanto, é fácil ver que uma produção é ou uma lista de palavras, ou uma lista de lista de produções. Os nomes das produções que começam com maiúsculas são terminais - esta é uma convenção na maioria das gramáticas. Eu não utilizei letras maiúsculas quando usando os métodos pois os métodos em Ruby nomeados desta maneira podem causar problemas adicionais quando chamados.&lt;/p&gt;

&lt;p&gt;Agora que realmente temos a gramática, necessitamos também de um método ajudante (helper), PAIP define rule-lhs, rule-rhs e rewrites (reescreve), mas o único que realmente precisamos aqui é o rewrites (Do arquivo &lt;em&gt;rule_based.rb)&lt;/em&gt;:&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;rewrites&lt;/span&gt;(&lt;span class=&quot;FunctionArgument&quot;&gt;category&lt;/span&gt;)
  &lt;span class=&quot;Variable&quot;&gt;&lt;span class=&quot;Variable&quot;&gt;$&lt;/span&gt;grammar&lt;/span&gt;[category]
&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;E, na verdade, poderíamos nos virar sem ele também, mas com ele a legibilidade fica melhor em relação a usar um indexador de acesso.&lt;/p&gt;

&lt;p&gt;A última coisa que precisamos é o método que realmente cria uma sentença a partir da gramática. Ele se parece com isso:&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;generate&lt;/span&gt;(&lt;span class=&quot;FunctionArgument&quot;&gt;phrase&lt;/span&gt;)
  &lt;span class=&quot;Keyword&quot;&gt;case&lt;/span&gt; phrase
  &lt;span class=&quot;Keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;Variable&quot;&gt;Array&lt;/span&gt;
    phrase.&lt;span class=&quot;FunctionName&quot;&gt;inject&lt;/span&gt;([]) { |&lt;span class=&quot;Variable&quot;&gt;sum&lt;/span&gt;, &lt;span class=&quot;Variable&quot;&gt;elt&lt;/span&gt;|  sum &lt;span class=&quot;Keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;generate&lt;/span&gt;(elt) }
  &lt;span class=&quot;Keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;Variable&quot;&gt;Symbol&lt;/span&gt;
    &lt;span class=&quot;FunctionName&quot;&gt;generate&lt;/span&gt;(&lt;span class=&quot;FunctionName&quot;&gt;rewrites&lt;/span&gt;(phrase).&lt;span class=&quot;FunctionName&quot;&gt;random_elt&lt;/span&gt;)
  &lt;span class=&quot;Keyword&quot;&gt;else&lt;/span&gt;
    [phrase]
  &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Se o que nos é perguntando para gerar é um array, então geraremos tudo o que está dentro deste array e então combinamos estes elementos.  Se a produção for um símbolo, então pegamos todas possíveis reescritas e pegamos um elemento aleatório delas. Atualmente toda produção tem uma reescrita, então o ramdom_elt não é estritamente necessário - mas como você verá mais tarde ele é bem bacana. E finalmente, se frase não for um array  nem um símbolo, nós apenas retornaremos a frase como o elemento gerado.&lt;/p&gt;

&lt;p&gt;Eu gosto especialmente do uso do método inject como uma versão mais geral de (mappend #gera a frase). Claro que, por legibilidade, seria possível também implementar o método mappend:&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;mappend&lt;/span&gt;(&lt;span class=&quot;FunctionArgument&quot;&gt;sym&lt;span class=&quot;FunctionArgument&quot;&gt;,&lt;/span&gt; list&lt;/span&gt;)
  list.&lt;span class=&quot;FunctionName&quot;&gt;inject&lt;/span&gt;([]) &lt;span class=&quot;Keyword&quot;&gt;do &lt;/span&gt;|&lt;span class=&quot;Variable&quot;&gt;sum&lt;/span&gt;, &lt;span class=&quot;Variable&quot;&gt;elt&lt;/span&gt;|
    sum &lt;span class=&quot;Keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;.&lt;span class=&quot;FunctionName&quot;&gt;send&lt;/span&gt;(sym, elt)
  &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Mas ao invés disso eu preferi utilizar inject diretamente, já que ele é mais idiomático. Note que esta versão do mappend não funciona exatamente igual ao mappend do Common Lisp, visto que ela não permite uma função lambda.&lt;/p&gt;

&lt;p&gt;Voltando ao método generate (gera). Se você rodasse generate(:sentence), você teria o mesmo tipo de saída do que rodando com a versão baseada no método - com a diferença de que mudar as regras é muito mais simples agora.&lt;/p&gt;

&lt;p&gt;Então, por exemplo, você pode usar esse código da &lt;em&gt;bigger_grammar.rb&lt;/em&gt; , que cria uma definição  grande de gramática e então usá-la como gramática padrão:&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
&lt;span class=&quot;Variable&quot;&gt;&lt;span class=&quot;Variable&quot;&gt;$&lt;/span&gt;bigger_grammar&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; {
  &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;sentence&lt;/span&gt; =&amp;gt; [[&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;noun_phrase&lt;/span&gt;, &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;verb_phrase&lt;/span&gt;]],
  &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;noun_phrase&lt;/span&gt; =&amp;gt; [[&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;Article&lt;/span&gt;, &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:'&lt;/span&gt;Adj*&lt;span class=&quot;UserDefinedConstant&quot;&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;Noun&lt;/span&gt;, &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:'&lt;/span&gt;PP*&lt;span class=&quot;UserDefinedConstant&quot;&gt;'&lt;/span&gt;&lt;/span&gt;], [&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;Name&lt;/span&gt;],
                   [&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;Pronoun&lt;/span&gt;]],
  &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;verb_phrase&lt;/span&gt; =&amp;gt; [[&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;Verb&lt;/span&gt;, &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;noun_phrase&lt;/span&gt;, &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:'&lt;/span&gt;PP*&lt;span class=&quot;UserDefinedConstant&quot;&gt;'&lt;/span&gt;&lt;/span&gt;]],
  &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:'&lt;/span&gt;PP*&lt;span class=&quot;UserDefinedConstant&quot;&gt;'&lt;/span&gt;&lt;/span&gt; =&amp;gt; [[], [&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;PP&lt;/span&gt;, &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:'&lt;/span&gt;PP*&lt;span class=&quot;UserDefinedConstant&quot;&gt;'&lt;/span&gt;&lt;/span&gt;]],
  &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:'&lt;/span&gt;Adj*&lt;span class=&quot;UserDefinedConstant&quot;&gt;'&lt;/span&gt;&lt;/span&gt; =&amp;gt; [[], [&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;Adj&lt;/span&gt;, &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:'&lt;/span&gt;Adj*&lt;span class=&quot;UserDefinedConstant&quot;&gt;'&lt;/span&gt;&lt;/span&gt;]],
  &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;PP&lt;/span&gt; =&amp;gt; [[&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;Prep&lt;/span&gt;, &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;noun_phrase&lt;/span&gt;]],
  &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;Prep&lt;/span&gt; =&amp;gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;%w(&lt;/span&gt;to in by with on&lt;span class=&quot;String&quot;&gt;)&lt;/span&gt;&lt;/span&gt;,
  &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;Adj&lt;/span&gt; =&amp;gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;%w(&lt;/span&gt;big little blue green adiabatic&lt;span class=&quot;String&quot;&gt;)&lt;/span&gt;&lt;/span&gt;,
  &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;Article&lt;/span&gt; =&amp;gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;%w(&lt;/span&gt;the a&lt;span class=&quot;String&quot;&gt;)&lt;/span&gt;&lt;/span&gt;,
  &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;Name&lt;/span&gt; =&amp;gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;%w(&lt;/span&gt;Pat Kim Lee Terry Robin&lt;span class=&quot;String&quot;&gt;)&lt;/span&gt;&lt;/span&gt;,
  &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;Noun&lt;/span&gt; =&amp;gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;%w(&lt;/span&gt;man ball woman table&lt;span class=&quot;String&quot;&gt;)&lt;/span&gt;&lt;/span&gt;,
  &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;Verb&lt;/span&gt; =&amp;gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;%w(&lt;/span&gt;hit took saw liked&lt;span class=&quot;String&quot;&gt;)&lt;/span&gt;&lt;/span&gt;,
  &lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;Pronoun&lt;/span&gt; =&amp;gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;%w(&lt;/span&gt;he she it these those that&lt;span class=&quot;String&quot;&gt;)&lt;/span&gt;&lt;/span&gt;}

&lt;span class=&quot;Variable&quot;&gt;&lt;span class=&quot;Variable&quot;&gt;$&lt;/span&gt;grammar&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;Variable&quot;&gt;&lt;span class=&quot;Variable&quot;&gt;$&lt;/span&gt;bigger_grammar&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Esta gramática inclui alguns elementos que fazem a saída um pouco melhor. Por exemplo, nós temos nomes (names) aqui, e também pronomes (pronouns). Uma das razões para esta gramática ser mais fácil de usar é porque podemos definir diferentes versões das produções. Então uma frase substantiva pode, por exemplo, o mesmo que definimos antes, mas também pode ser apenas um único nome ou um único pronome. Nós usamos isso para lidar com as produções recursivas PP* e Adj*. Você pode também ver porque as produções são definidas com um array dentro de um array. Isto é para permitir opções nesta gramática.&lt;/p&gt;

&lt;p&gt;Uma sentença típica desta gramática (chamando generate(:sentence)) resulta em [&#8220;Terry&#8221;, &#8220;saw&#8221;, &#8220;that&#8221;] (Terry viu aquilo)  ou [&#8220;Lee&#8221;, &#8220;took&#8221;, &#8220;the&#8221;, &#8220;blue&#8221;, &#8220;big&#8221;, &#8220;woman&#8221;] (Lee pegou a grande mulher azul&#8221;).&lt;/p&gt;

&lt;p&gt;Portanto é mais fácil mudar estas regras. Além disso, acredite que é mais fácil ler e entender as regras aqui. Mas uma das mudanças mais importantes trazidas pela abordagem orientada a dados é que você pode usar as mesmas regras para diferentes propósitos. Diga que queremos uma árvore de sentenças, que inclui o nome da produção usada para esta parte na árvore. Isto é tão simples quanto definir um novo método generate (no arquivo &lt;em&gt;generate_tree.rb&lt;/em&gt;):&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;bigger_grammar&lt;span class=&quot;String&quot;&gt;'&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;generate_tree&lt;/span&gt;(&lt;span class=&quot;FunctionArgument&quot;&gt;phrase&lt;/span&gt;)
  &lt;span class=&quot;Keyword&quot;&gt;case&lt;/span&gt; phrase
  &lt;span class=&quot;Keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;Variable&quot;&gt;Array&lt;/span&gt;
    phrase.&lt;span class=&quot;FunctionName&quot;&gt;map&lt;/span&gt; { |&lt;span class=&quot;Variable&quot;&gt;elt&lt;/span&gt;| &lt;span class=&quot;FunctionName&quot;&gt;generate_tree&lt;/span&gt;(elt) }
  &lt;span class=&quot;Keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;Variable&quot;&gt;Symbol&lt;/span&gt;
    [phrase] &lt;span class=&quot;Keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;generate_tree&lt;/span&gt;(&lt;span class=&quot;FunctionName&quot;&gt;rewrites&lt;/span&gt;(phrase).&lt;span class=&quot;FunctionName&quot;&gt;random_elt&lt;/span&gt;)
  &lt;span class=&quot;Keyword&quot;&gt;else&lt;/span&gt;
    [phrase]
  &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Esse código segue os mesmos padrões que o generate, com algumas pequenas mudanças. Você pode ver que no lugar de anexar os resutados do array em conjunto, nó apenas usamos  o método map em cada elemento, Isto porque precisamos de mais subarrays para criar uma árvore. Da mesma maneira quando temos um símbolo nós prefixiamos isto ao array gerado. E, realmento, nesta altura é bem interessante darmos uma olhada na versão Lisp deste código:&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
(defun generate&lt;span class=&quot;Keyword&quot;&gt;-&lt;/span&gt;tree (phrase)
  (cond ((listp phrase)
         (mapcar &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt;'generate-tree phrase))&lt;/span&gt;
        ((rewrites phrase)
         (cons phrase
               (generate&lt;span class=&quot;Keyword&quot;&gt;-&lt;/span&gt;tree (random&lt;span class=&quot;Keyword&quot;&gt;-&lt;/span&gt;elt (rewrites phrase)))))
        t (list phrase)))
&lt;/pre&gt;

&lt;p&gt;E você pode ver que a estrutura é, na maior parte, a mesma. Eu fiz algumas escolhas diferentes na representação, o que significa que estou checando se a frase é um símbolo ao vés de ver se a reescrita de um símbolo é não nula. A chamada a mapcar é equivalente a chamada de map em Ruby.&lt;/p&gt;

&lt;p&gt;O que ele gera então? Chamando-o como &#8220;pp generate_tree(:sentence)&#8221;, obtenho algo como isto:&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
[&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;sentence&lt;/span&gt;,
 [&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;noun_phrase&lt;/span&gt;, [&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;Name&lt;/span&gt;, &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;Lee&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;]],
 [&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;verb_phrase&lt;/span&gt;,
  [&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;Verb&lt;/span&gt;, &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;saw&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;],
  [&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;noun_phrase&lt;/span&gt;,
   [&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;Article&lt;/span&gt;, &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;the&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;],
   [&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&amp;quot;&lt;/span&gt;Adj*&lt;span class=&quot;UserDefinedConstant&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
    [&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;Adj&lt;/span&gt;, &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;green&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;],
    [&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&amp;quot;&lt;/span&gt;Adj*&lt;span class=&quot;UserDefinedConstant&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;]],
   [&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&lt;/span&gt;Noun&lt;/span&gt;, &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;table&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;],
   [&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&amp;quot;&lt;/span&gt;PP*&lt;span class=&quot;UserDefinedConstant&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;]],
  [&lt;span class=&quot;UserDefinedConstant&quot;&gt;&lt;span class=&quot;UserDefinedConstant&quot;&gt;:&amp;quot;&lt;/span&gt;PP*&lt;span class=&quot;UserDefinedConstant&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;]]]
&lt;/pre&gt;

&lt;p&gt;que mapeia muito bem para nossa gramática. Nós podemos gerar todas possíveis sentenças para uma gramática sem recursão, usando a mesma abordagem orientada a dados.&lt;/p&gt;

&lt;p&gt;O  código para esta abordagem é encontrado em &lt;em&gt;generate_all.rb&lt;/em&gt;:&lt;/p&gt;

&lt;pre class=&quot;idle&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;generate_all&lt;/span&gt;(&lt;span class=&quot;FunctionArgument&quot;&gt;phrase&lt;/span&gt;)
  &lt;span class=&quot;Keyword&quot;&gt;case&lt;/span&gt; phrase
  &lt;span class=&quot;Keyword&quot;&gt;when&lt;/span&gt; []
    [[]]
  &lt;span class=&quot;Keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;Variable&quot;&gt;Array&lt;/span&gt;
    &lt;span class=&quot;FunctionName&quot;&gt;combine_all&lt;/span&gt;(&lt;span class=&quot;FunctionName&quot;&gt;generate_all&lt;/span&gt;(phrase[&lt;span class=&quot;Number&quot;&gt;0&lt;/span&gt;]),
                &lt;span class=&quot;FunctionName&quot;&gt;generate_all&lt;/span&gt;(phrase[&lt;span class=&quot;Number&quot;&gt;1&lt;/span&gt;..&lt;span class=&quot;Keyword&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;Number&quot;&gt;1&lt;/span&gt;]))
  &lt;span class=&quot;Keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;Variable&quot;&gt;Symbol&lt;/span&gt;
    &lt;span class=&quot;FunctionName&quot;&gt;rewrites&lt;/span&gt;(phrase).&lt;span class=&quot;FunctionName&quot;&gt;inject&lt;/span&gt;([]) { |&lt;span class=&quot;Variable&quot;&gt;sum&lt;/span&gt;, &lt;span class=&quot;Variable&quot;&gt;elt&lt;/span&gt;|  sum &lt;span class=&quot;Keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;generate_all&lt;/span&gt;(elt) }
  &lt;span class=&quot;Keyword&quot;&gt;else&lt;/span&gt;
    [[phrase]]
  &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;FunctionName&quot;&gt;combine_all&lt;/span&gt;(&lt;span class=&quot;FunctionArgument&quot;&gt;xlist&lt;span class=&quot;FunctionArgument&quot;&gt;,&lt;/span&gt; ylist&lt;/span&gt;