tag:blogger.com,1999:blog-13879967204364506492024-03-13T13:42:45.010-03:00KodumaroAs sombras da programaçãoℭacilhας, ℒa ℬatalemahttp://www.blogger.com/profile/14265747724618147106noreply@blogger.comBlogger135125tag:blogger.com,1999:blog-1387996720436450649.post-82257133869633762882016-03-15T20:58:00.001-03:002016-08-31T18:54:01.327-03:00Mudança de endereço<div style="align: justify;">
Como o <a href="http://blogger.com/">Blogger.com</a> resolveu restringir as possibilidades de edição, estamos transferindo o Kodumaro para minha página pessoal.<br />
<br />
O nome endereço é <a href="http://cacilhas.info/kodumaro">ℭacilhας.INFO/Kodumaro</a>. Você já pode acessar nosso primeiro artigo: <a href="http://cacilhas.info/kodumaro/2016/03/sml.html">Standard ML</a>.
</div>
[]’sℭacilhας, ℒa ℬatalemahttp://www.blogger.com/profile/14265747724618147106noreply@blogger.com0tag:blogger.com,1999:blog-1387996720436450649.post-32504749279613678722015-11-28T09:30:00.002-03:002015-11-28T09:43:52.469-03:00A outra porta<div style="align: justify;">
<img border="0" src="http://4.bp.blogspot.com/-P7eBitfW9TY/VlmVHcgOKsI/AAAAAAAADnI/msc5OAvT5a8/s320/monty-hall.jpg" style="border-bottom-style: none; cursor: crosshair; float: left; margin-bottom: 10px; margin-left: 0pt; margin-right: 10px; margin-top: 0pt; text-align: justify;" />
O <a href="https://pt.wikipedia.org/wiki/Problema_de_Monty_Hall">Paradoxo de Monty Hall</a> consiste no fato de que, em se descartando algumas escolhas erradas, as que sobram desconhecidas combinam as probabilidades de estarem certas das descartadas.<br/>
<br/>
Por exemplo, em três portas, atrás de uma há um prêmio. Você escolhe uma das três e o mestre de cerimônias abre uma das outras duas, mostrando que o carro <strong>não</strong> está lá. A porta que você escolheu continua com ⅓ de chance de ser a correta, mas a outra porta não escolhida ganha a possibilidade de conter o prêmio da que foi aberta, passando a ser de ⅔.<br/>
<br/>
Isso acontece porque a porta com o prêmio <strong>e</strong> a porta escolhida (independente de ser a do prêmio ou não) influenciaram juntas na escolha da porta a ser aberta, mesmo que você não saiba qual a porta do prêmio.<br/>
<br/>
Muita gente discorda disso, diz que se sobraram duas portas, as chances passa a ser ½+½ e não ⅓+⅔. Pode-se ficar horas (ou dias) discutindo isso. A melhor forma de se verificar isso é testando!<br/>
<br/>
Vamos escrever uma classe que <code>MasterOfCeremonies</code> que oferece três portas, sendo uma premiada:
</div>
<pre><code class="prettyprint">from random import choice
class MasterOfCeremonies:
__slots__ = '__doors __prize __choice'.split()
def __init__(self) -> None:
self.__doors = 'ABC'
self.__prize = choice(self__doors)
self.__choice = None
@property
def doors(self) -> str:
return self.__doors
@property
def wins(self) -> bool:
if not self.__choice:
raise TypeError
return self.__choice == self.__prize
def choose(self, door: str) -> None:
if door not in self.__doors:
raise ValueError
self.__choice = door</code></pre>
<br/>
<div style="align: justify;">
Nossa classe guarda três portas (<code>A</code>, <code>B</code> e <code>C</code>), apenas uma premiada. Para testar, podemos jogar mil vezes e vermos em quantas vezes ganhamos.<br/>
<br/>
Para facilitar, vamos escolher sempre a porta do meio:
</div>
<pre><code class="prettyprint">if __name__ == '__main__':
wins = 0
for _ in range(1000):
wc = MasterOfCeremonies()
door = wc.doors[1] # sempre a porta do meio
wc.choose(door)
wins += 1 if wc.wins else 0
print('Wins:', wins)</code></pre>
<br/>
<div style="align: justify;">
Não importa quantas vezes você execute esse programa, vai sempre retornar um valor próximo de 333 vitórias – o que faz todo sentido! São mil lances, ⅓ dá 333.<br/>
<br/>
Agora vamos adicionar o paradoxo: um método que abre aleatoriamente uma porta sem prêmio e outro que permite ao jogador trocar para a porta fechada restante.<br/>
<br/>
Dentro da classe <code>MasterOfCeremonies</code> adicione os seguintes métodos:
</div>
<pre><code class="prettyprint"> def remove(self) -> None:
if not self.__choice or len(self.__doors) == 2:
raise TypeError
doors = set(self.__doors)
others = doors - {self.__choices, self.__prize}
other = choice(list(others))
doors -= {other}
self.__doors = ''.join(list(doors))
def change(self) -> str:
if not (self.__choice and len(self.__doors) == 2):
raise TypeError
doors = set(self.__doors)
doors -= {self.__choice}
self.__choice = list(doors)[0]
return self.__choice</code></pre>
<br/>
<div style="align: justify;">
Agora vamos mudar nosso procedimento principal para trocar de porta após a abertura (<code>remove</code>) da porta sem prêmio:
</div>
<pre><code class="prettyprint">if __name__ == '__main__':
wins = 0
for _ in range(1000):
wc = MasterOfCeremonies()
door = wc.doors[1] # sempre a porta do meio
mc.choose(door)
mc.remove() # descarta uma das portas sem prêmio
door = mc.change() # troca a porta escolhida
wins += 1 if wc.wins else 0
print('Wins:', wins)</code></pre>
<br/>
<div style="align: justify;">
Agora vem o <em>mindfuck</em>: não importa quantas vezes você execute esse programa, o número de vitórias em mil será sempre por volta de 667, ⅔ das tentativas!<br/>
<br/>
Ou seja, o paradoxo realmente <strong>funciona</strong>. Volte lá na <a href="https://pt.wikipedia.org/wiki/Problema_de_Monty_Hall">Wikipédia</a>, porque a explicação é realmente muito boa. ;-)
</div><br/>
[]’s<br/>
<br/>
<div style="align: justify; font-size: x-small;">
PS: Eu ia escrever os códigos em <a href="http://www.swi-prolog.org/">Prolog</a>, pois sua abordagem de lidar com domínio de verdades é muito conveniente para este problema, no entanto <a href="https://www.python.org/">Python</a> é muito mais didática: já basta a dificuldade em entender o Paradoxo de Monty Hall, não precisamos de mais complicação com uma implementação complexa.
</div>ℭacilhας, ℒa ℬatalemahttp://www.blogger.com/profile/14265747724618147106noreply@blogger.com0tag:blogger.com,1999:blog-1387996720436450649.post-8722671239304870732015-08-19T12:04:00.000-03:002015-08-19T12:10:51.342-03:00Processamento e significância de dados<div align="justify">
<img alt="Glider"
src="http://2.bp.blogspot.com/_rGfO7DAuOSE/SwSZGIY_eXI/AAAAAAAAATA/Gh-qDqdTMX0/s200/glider.png"
style="border: none; cursor: crosshair; float: left; height: 55px; margin: 0 10px 10px 0; width: 55px;" />
Em <a href="http://pt.wikipedia.org/wiki/Tecnologias_da_informação_e_comunicação">T.I.C., Tecnologias da Informação e da Comunicação</a>, há uma teoria muito importante de processamento e significância de dados.<br/>
<br/>
Há três níveis de dados/informações, e entender esses níveis é essencial para a aplicação prática de <a href="http://pt.wikipedia.org/wiki/Mineração_de_dados"><em>data mining</em></a>.
</div><br/>
<h3>Dado</h3>
<div align="justify">Dado é todo e qualquer elemento cru de informação, como números, textos, nomes, datas e até combinações de outros dados.<br/>
<br/>
Por exemplo, a quantidade de pessoas na sala, seus nomes, suas datas de nascimento, etc.<br/>
<br/>
Conceitos como “não sei” (termo técnico: <em>indefinido</em>), “não existe” (t.t.: <em>nulo</em>) e “vou ver” (t.t.: <em>futuro</em>) <strong>também</strong> são dados válidos.
</div><br/>
<h3>Informação</h3>
<div align="justify">Informação é o resultado da <strong>contextualização</strong> do dado, ou seja, o significado ou valor do dado dentro de um contexto. Quais as relações entre os dados.<br/>
<br/>
No nosso exemplo, como cada pessoa se relaciona como cada uma das outras.
</div><br/>
<h3>Conhecimento</h3>
<div align="justify">O terceiro nível é o conhecimento, que é, dado um conjunto de informações, como posso tornar isso útil.<br/>
<br/>
Por exemplo, dadas as pessoas na sala e suas relações, como isso pode ser útil pra mim e como eu posso ser útil nesse domínio.
</div><br/>
[]’s
ℭacilhας, ℒa ℬatalemahttp://www.blogger.com/profile/14265747724618147106noreply@blogger.com0tag:blogger.com,1999:blog-1387996720436450649.post-86968389329679992512015-08-08T23:11:00.002-03:002016-05-21T09:28:43.078-03:00Instalando MoonScript sobre LuaJIT<div align="justify">
<blockquote>Atualizado no <a href="http://cacilhas.info/kodumaro/2016/05/moonscript.html"><em>blog</em> novo</a>.</blockquote>
<br/>
<img style="border: none; margin: 0pt 10px 10px 0pt; float: left; cursor: crosshair;" src="https://3.bp.blogspot.com/-2-bVE1IkLSQ/Vca393QTe1I/AAAAAAAAC0M/CSqeB0Cskrg/s200/moonscript.jpg" alt="MoonScript"><br/>
Colocar <a href="http://moonscript.org/">MoonScript</a> para trabalhar com <a href="http://luajit.org/">LuaJIT</a> não é trivial. É preciso uma série de pequenos <em>hacks</em> pra funcionar.<br/>
<br/>
Vamos começar pelas dependências.<br/><br/>
<h3>Dependências</h3>
MoonScript depende de quatro outros módulos para funcionar:
<ul>
<li><a href="http://luaforge.net/projects/alt-getopt/"><code>alt-getopt</code></a></li>
<li><a href="http://keplerproject.github.io/luafilesystem/">LuaFileSystem</a></li>
<li>LPeg</li>
</ul><br/>
Instale <code>alt-getopt</code> normalmente no <code>LUA_PATH</code> de seu LuaJIT. Aqui para mim é <code>/usr/share/lua/jit</code>.<br/>
<br/>
Para instalar LuaFileSystem, clone o repositório do <a href="https://github.com/keplerproject/luafilesystem">GitHUB</a> e não se esqueça de editar o arquivo <code>config</code>. As mudanças principais são:
<pre><code class="prettyprint">PREFIX=/usr
LUA_LIBDIR=$(PREFIX)/lib/lua/jit
LUA_INC=$(PREFIX)/include/luajit-2.0</code></pre>
<br/>
Isso considerando que seu <code>LUA_CPATH</code> esteja em <code>/usr/lib/lua/jit</code>.<br/>
<br/>
Compile e instale normalmente.<br/>
<br/>
Já LPeg merece uma atenção extra, já que ele <strong>não</strong> funciona com LuaJIT. No lugar, use <a href="https://github.com/sacek/LPegLJ">LPegLJ</a>.<br/>
<br/>
Clone e instale LPegLJ no seu <code>LUA_PATH</code>, depois execute o seguinte comando:
<pre><code>cd /usr/share/lua/jit/
sudo ln -s lpeglj.lua lpeg.lua</code></pre><br/>
Isso fará com que MoonScript pense tratar-se do LPeg original.<br/>
<br/>
<h3>Instalando MoonScript</h3>
Com as três dependências instaladas, clone o projeto do <a href="https://github.com/leafo/moonscript">GitHUB</a>. Edite o <code>Makefile</code>, substituindo as ocorrências de <code>lua5.1</code> e <code>lua</code> por <code>luajit</code>.<br/>
<br/>
Remova as entradas <code>local</code> e <code>global</code> do <code>Makefile</code>.<br/>
<br/>
Edite o <em>hashbang</em> dos arquivos <code>bin/moon</code> e <code>bin/moonc</code> trocando <code>lua</code> por <code>luajit</code>.<br/>
<br/>
Execute <code>make compile</code>.<br/>
<br/>
Copie os diretórios <code>moon/</code> e <code>moonscript/</code> para seu <code>LUA_PATH</code>.<br/>
<br/>
Copie os arquivos <code>bin/moon</code> e <code>bin/moonc</code> para o diretório <code>/usr/bin</code> do sistema.<br/>
<br/>
E pronto! Já deve estar funcionando! Qualquer dúvida, me avisem pra eu revisar o texto.
</div><br/>
[]’sℭacilhας, ℒa ℬatalemahttp://www.blogger.com/profile/14265747724618147106noreply@blogger.com1tag:blogger.com,1999:blog-1387996720436450649.post-38259924483142846252015-06-22T22:58:00.000-03:002016-05-21T09:30:08.513-03:00MoonScript<div style="text-align: justify;">
<blockquote>Adaptado no <a href="http://cacilhas.info/kodumaro/2016/05/moonscript.html"><em>blog</em> novo</a>.</blockquote>
<img style="border: none; margin: 0pt 10px 10px 0pt; float: left; cursor: crosshair;" src="https://3.bp.blogspot.com/-2-bVE1IkLSQ/Vca393QTe1I/AAAAAAAAC0M/CSqeB0Cskrg/s200/moonscript.jpg" alt="MoonScript"> Há muito pouco tempo atrás um amigo meu me sugeriu dar atenção à <a href="http://moonscript.org/">MoonScript</a>. Admito que eu via a linguagem com preconceito, mesmo assim resolvi dar uma olhada.<br/>
<br/>
Resultado: todos os meus códigos em <a href="http://www.lua.org/">Lua</a> acabaram convertidos para MoonScript. :-)<br/>
<br/>
A linguagem é extremamente enxuta, limpa e poderosa. Não vou entrar em detalhes, se estiver curioso, leia o <a href="http://moonscript.org/reference/">guia da linguagem</a>.<br/>
<br/>
Mas também não puxei assunto por nada, vou dar alguns exemplos.
</div>
<br/>
<h3>Paradigma Funcional</h3>
<div style="text-align: justify;">
Para lidar com o paradigma funcional, a sintaxe de MoonScript é bem mais concisa e que a de Lua. Por exemplo, o <a href="http://kodumaro.blogspot.in/2014/08/combinador-de-ponto-fixo.html">combinador Y</a>.<br/>
<br/>
Lua é uma linguagem estrita e não suporta o combinador Y em sua forma <em>lazy</em>. Como MoonScript é compilado para código Lua, sofre do mesmo mal. Assim, é preciso usar o combinador Z, que é versão estrita do combinador Y.<br/>
<br/>
O combinador Z é definido como: <code>λf.(λx.xx)(λx.f(λv.xxv))</code>. Isso é facilmente representado em MoonScript:
</div>
<pre><code class="prettyprint">Z = (f using nil) -> ((x) -> x x) (x) -> f (...) -> (x x) ...</code></pre>
<br/>
<div style="text-align: justify;">
Com isso é possível, por exemplo, implementar facilmente o <em>quick sort</em>:
</div>
<pre><code class="prettyprint">Z = (f using nil) -> ((x) -> x x) (x) -> f (...) -> (x x) ...
tconcat = (...) -> [e for t in *{...} for e in *t]
Z (qsort using tconcat) ->
(xs) ->
if #xs <= 1
xs
else
x, xs = xs[1], [e for e in *xs[2,]]
lesser = [e for e in *xs when e <= x]
greater = [e for e in *xs when e > x]
tconcat (qsort lesser), {x}, (qsort greater)</code></pre>
<br/>
<h3>Orientação a Objetos</h3>
<div style="text-align: justify;">
Em Lua é preciso toda uma ginástica com <a href="http://www.lua.org/pil/13.html">metatabelas</a> para simular eficientemente orientação a objetos. MoonScript tem suporte a classes na linguagem.<br/>
<br/>
Por exemplo, podemos criar uma pilha (<em>stack</em>) facilmente:
</div>
<pre><code class="prettyprint">import bind_methods from assert require "moon"
class Stack
list: nil
set: (x) =>
@list =
next: @list
value: x
get: =>
v = nil
{value: v, next: @list} = @list if @list
v
bind_methods Stack!</code></pre>
<br/>
<h3>LuaJIT</h3>
<div style="text-align: justify;">
Como MoonScript compila para código Lua tradicional, você pode gerar código para virtualmente qualquer plataforma que rode Lua, como <a href="http://luajit.org/">LuaJIT</a> e <a href="https://love2d.org/">LÖVE</a>.<br/>
<br/>
Por exemplo, você pode usar <em>C-structs</em> e metatipos:
</div>
<pre><code class="prettyprint">ffi = assert require "ffi"
import sqrt from math
ffi.cdef [[
typedef struct { double x, y; } point_t;
]]
local Point = ffi.metatype "point_t",
__add: (o) => Point @x + o.x, @y + o.y
__len: => @\hypot!
__tostring: => "(#{@x}, #{@y})"
__index:
area: => @x * @y
hypot: => sqrt @x*@x + @y*@y
Point</code></pre><br/>
<pre><code>bash$ <strong>luajit</strong>
LuaJIT 2.0.3 -- Copyright (C) 2005-2014 Mike Pall. http://luajit.org/
JIT: ON CMOV SSE2 SSE3 SSE4.1 fold cse dce fwd dse narrow loop abc sink fuse
> <strong>moon = assert(require "moonscript.base")</strong>
> <strong>Point = (moon.loadfile "point.moon")()</strong>
> <strong>p = Point(3, 4)</strong>
> <strong>= tostring(p)</strong>
(3, 4)
> <strong>= p:area()</strong>
12
> <strong>= #p</strong>
5
></pre></code>
<div style="text-align: justify;">
Bem, acho que já fiz propaganda suficiente da linguagem. ;-)
</div>
<br/>
[]’s
<br/>ℭacilhας, ℒa ℬatalemahttp://www.blogger.com/profile/14265747724618147106noreply@blogger.com0tag:blogger.com,1999:blog-1387996720436450649.post-77945385622986443212015-04-18T11:36:00.002-03:002015-11-28T21:36:34.147-03:00Tipos em Cython<div style="text-align: justify;">
<img alt="" src="http://3.bp.blogspot.com/-5LrIxts7emc/VTGWqBrocdI/AAAAAAAABk8/5YL2ytP4VUA/s1600/cython.jpg" style="border: none; cursor: crosshair; float: left; margin: 0pt 10px 10px 0pt;" /> <a href="http://kodumaro.blogspot.com.br/2015/04/cython.html">Ontem</a> fiz uma pequena introdução ao <a href="http://cython.org/">Cython</a>.<br/>
<br/>
Cython é uma plataforma que traduz código <a href="https://www.python.org/">Python</a> para C e o compila em biblioteca compartilhada importável no próprio Python. A linguagem em si é um <em>superset</em> de Python, com tipagem estática ou dinâmica (<em>duck-typing</em>) e suporte a código especial que pode ser traduzido diretamente para C.<br/>
<br/>
Uma parte importante de Cython é sua tipagem estática, mas os tipos pode ser um pouco diferentes de Python.<br/>
<br/>
Há tipos específicos, como <code>struct</code> e <code>enum</code>, que são traduzidos diretamente para o equivalente C, e tipo de extensão (<code>cdef class</code>). Entre eles:<br/>
</div><br/>
<table>
<thead>
<tr><th>Tipo Cython</th><th>Tipo C</th><th>Coerção para Python 3</th></tr>
</thead>
<tbody>
<tr>
<td><code>bool</code></td>
<td><code>PyLongObject *</code></td>
<td><code>bool</code></td>
</tr>
<tr>
<td><code>bint</code></td>
<td><code>int</code></td>
<td><code>bool</code></td>
</tr>
<tr>
<td><code>size_t</code></td>
<td><code>size_t</code></td>
<td><code>int</code></td>
</tr>
<tr>
<td><code>char</code></td>
<td><code>char</code></td>
<td><code>int</code></td>
</tr>
<tr>
<td><code>unsigned char</code></td>
<td><code>unsigned char</code></td>
<td><code>int</code></td>
</tr>
<tr>
<td><code>int</code></td>
<td><code>int</code></td>
<td><code>int</code></td>
</tr>
<tr>
<td><code>long</code></td>
<td><code>long</code></td>
<td><code>int</code></td>
</tr>
<tr>
<td><code>long long</code></td>
<td><code>long long</code></td>
<td><code>int</code></td>
</tr>
<tr>
<td><code>float</code></td>
<td><code>float</code></td>
<td><code>float</code></td>
</tr>
<tr>
<td><code>double</code></td>
<td><code>double</code></td>
<td><code>float</code></td>
</tr>
<tr>
<td><code>const char *</code></td>
<td><code>const char *</code></td>
<td><code>bytes</code></td>
</tr>
<tr>
<td><code>bytes</code></td>
<td><code>PyBytesObject *</code></td>
<td><code>bytes</code></td>
</tr>
<tr>
<td><code>const Py_UNICODE *</code></td>
<td><code>const Py_UNICODE *</code></td>
<td><code>str</code></td>
</tr>
<tr>
<td><code>unicode</code></td>
<td><code>struct PyUnicodeObject</code></td>
<td><code>str</code></td>
</tr>
<tr>
<td><code>object</code></td>
<td><code>PyObject *</code></td>
<td><code>object</code></td>
</tr>
<tr>
<td><code>list</code></td>
<td><code>PyListObject *</code></td>
<td><code>list</code></td>
</tr>
<tr>
<td><code>dict</code></td>
<td><code>PyDictObject *</code></td>
<td><code>dict</code></td>
</tr>
<tr>
<td><code>set</code></td>
<td><code>PySetObject *</code></td>
<td><code>set</code></td>
</tr>
<tr>
<td><code>tuple</code></td>
<td><code>PyTupleObject *</code></td>
<td><code>tuple</code></td>
</tr>
<tr>
<td><code>void *</code></td>
<td><code>void *</code></td>
<td>sem equivalência</td>
</tr>
<tr>
<td><code>struct <em>S</em></code></td>
<td><code>struct <em>S</em></code></td>
<td><code>dict</code></td>
</tr>
<tr>
<td><code>enum <em>E</em></code></td>
<td><code>enum <em>E</em></code></td>
<td><code>int</code></td>
</tr>
</tbody>
</table><br/>
<div style="text-align: justify;">
Todos os modificadores C (<code>unsigned</code>, <code>const</code>, <code>long</code>, <code>*</code>…) são aceitos. Na coerção de tipos, também é aceito <code>&</code>. Se um valor numérico for recebido por uma variável do tipo <code>object</code>, será usado <code>PyLongObject *</code> (inteiro de tamanho arbitrário) ou <code>PyFloatObject *</code> (ponto flutuante, equivalente a <code>double</code> de C).
</div>
<br/>
[]’s<br />
ℭacilhας, La Batalemaℭacilhας, ℒa ℬatalemahttp://www.blogger.com/profile/14265747724618147106noreply@blogger.com0tag:blogger.com,1999:blog-1387996720436450649.post-42626865911107642262015-04-17T21:36:00.001-03:002015-06-19T13:10:11.383-03:00Cython<div style="text-align: justify;">
<img alt="" src="http://3.bp.blogspot.com/-5LrIxts7emc/VTGWqBrocdI/AAAAAAAABk8/5YL2ytP4VUA/s1600/cython.jpg" style="border: none; cursor: crosshair; float: left; margin: 0pt 10px 10px 0pt;" /> Nas últimas semanas tenho desenvolvido uma aplicação usando <a href="http://cython.org">Cython</a> e me surpreendi com o resultado.<br/>
<br/>
Comecei usando o Cython apenas para compilar código Python – o que de fato rendeu o aumento de desempenho prometido –, mas então resolvi ir mais longe pra ver o quanto poderia extrair dessa plataforma: comecei a usar tipagem estática, funções C (<code>cdef</code>) e depois acabei migrando minhas classes para tipos de extensão (<code>cdef class</code>es).<br/>
<br/>
A cada novo passo era perceptível o crescimento do desempenho e da coerência geral do código. Minha única crítica é quanto aos testes: o código fica muito difícil de ser testado, já que não é possível fazer <em>monkey-patch</em> para colocar os <em>mocks</em>.<br/>
<br/>
Segundo a documentação, ao compilar código Python com Cython, você tem um aumento de 35% no desempenho do código. Usando a tipagem estática, o aumento é de 300% e usando funções C e tipos de extensão o aumento é de aproximadamente 15.000%.<br/>
<br/>
Não posso confirmar esses números, pois não fiz medições exatas, mas uma fila do RabbitMQ que enchia com 6, 7 mil mensagens, encheu com 64 mil no mesmo período de tempo (eu estava fazendo apenas carga, sem consumir a fila).<br/>
<br/>
Uma coisa que gostei muito no Cython é o <em>feeling</em>: tem uma pegada bastante parecida com a do <a href="https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/Introduction/Introduction.html">Objective C</a>, o que faz sentido.<br/>
<br/>
Vou dar um exemplo da própria <a href="http://docs.cython.org/src/quickstart/cythonize.html">documentação</a> do Cython:<br/>
<br/>
Dado o seguinte código Python puro:
<pre><code class="prettyprint">def f(x):
return x**2-x
def integrate_f(a, b, N):
s = 0
dx = (b-a)/N
for i in range(N):
s += f(a+i*dx)
return s * dx</code></pre>
Você pode salvar esse código em <code>integrate.pyx</code> e compilá-lo assim:
<pre><code>bash$ <strong>cythonize -ib integrate.pyx</strong></code></pre>
Isso irá gerar o código equivalente em C (<code>integrate.c</code>) e compilá-lo na biblioteca <code>integrate.so</code>, que pode ser diretamente importada em Python:
<pre><code>bash$ <strong>python</strong>
>>> <strong>from integrate import integrate_f</strong>
>>></code></pre>
Se você tiver o <a href="http://ipython.org">IPython</a>, pode usar o Cython no <em>prompt</em>:
<pre><code>bash$ <strong>ipython</strong>
Python 2.7.9 (default, Jan 7 2015, 11:49:12)
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.56)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> <strong>%load_ext Cython</strong>
>>> <strong>%%cython</strong>
<strong>from integrate cimport integrate_f</strong></code></pre>
De qualquer forma, só usando a biblioteca compilada em vez do código Python importado, Cython já promete um aumento de 35% de <em>performance</em> – o que não me frustrou.<br/>
<br/>
Além disso, podemos adicionar tipagem ao código: Cython é um <em>superset</em> em Python, ou seja, é uma linguagem em si e um código Python é também código válido Cython.
<pre><code class="prettyprint">def f(double x):
return x**2-x
def integrate_f(double a, double b, int N):
cdef:
int i
double s, dx
s = 0
dx = (b-a)/N
for i in range(N):
s += f(a+i*dx)
return s * dx</code></pre>
Segundo a documentação, isso garante um desempenho 4 vezes superior ao de Python.<br/>
<br/>
No entanto ainda é possível otimizar mais ainda o código! Cython tem uma sintaxe específica que gera código C diretamente, <code>cdef</code>:
<pre><code class="prettyprint">cdef double f(double x) except? -2:
return x**2-x
def integrate_f(double a, double b, int N):
cdef:
int i
double s, dx
s = 0
dx = (b-a)/N
for i in range(N):
s += f(a+i*dx)
return s * dx</code></pre>
O desempenho dessa função <code>f</code> em C promete ser 150 vezes melhor do que a mesma função em Python puro.<br/>
<br/>
O <code>except? -2</code> na função é usado para passar exceções para o código C. Em um outro momento posso entrar em mais detalhes.<br/>
<br/>
<h3>Tipo de extensão</h3>
<a href="http://docs.cython.org/src/tutorial/cdef_classes.html">Tipos de extensão</a> são equivalentes às classes de Python, porém mais restritos e muito mais eficientes.<br/>
<br/>
Por exemplo, da a seguinte classe:
<pre><code class="prettyprint">class Consumer(object):
def __init__(self, backend):
self.backend = backend
def run(self, handler):
resp = self.backend.get()
return handler.handle(resp)</code></pre>
Considerando que as instâncias só serão executadas em Cython, o código equivalente estaria em dois arquivos, o primeiro <code>consumer.pxd</code>:
<pre><code class="prettyprint">from backends.base cimport Backend
from handlers.base cimport Handler
cdef class Consumer:
cdef:
Backend backend
int run(self, Handler handler) except? -1</code></pre>
Esse código <code>.pxd</code> equivale ao cabeçalho <code>.h</code> de C. Agora, o arquivo de implementação deve ser chamado <code>consumer.pyx</code>:
<pre><code class="prettyprint">from backends.base cimport Backend
from handlers.base cimport Handler
cdef class Consumer:
def __cinit__(self, Backend backend):
self.backend = backend
cdef int run(self, Handler handler) except? -1:
cdef dict resp = self.backend.get()
return handler.handle(resp)</code></pre>
Esse código promete ser muito mais eficiente que sua versão em Python, infelizmente métodos declarados como <code>cdef</code> são acessíveis apenas em C (e em Cython). Para que o método seja acessível em Python, ele deve ser criado como um método Python comum (<code>def</code>) ou pode ser usado <code>cpdef</code>.<br/>
<br/>
O comando <code>cpdef</code> (C/Python <code>def</code>) cria a função C (como <code>cdef</code>) e um <em>wrapper</em> em Python para torná-la acessível. Se o módulo for importando com <code>cimport</code>, será usada a função C original; se for importado com o clássico <code>import</code>, será usado o <em>wrapper</em>.<br/>
<br/>
<h3>Conclusão</h3>
Até agora não tive motivos para me arrepender de usar Cython, recomendo.
</div>
<br/>
[]’s<br />
ℭacilhας, La Batalemaℭacilhας, ℒa ℬatalemahttp://www.blogger.com/profile/14265747724618147106noreply@blogger.com0tag:blogger.com,1999:blog-1387996720436450649.post-91216434924656432642015-04-15T00:12:00.000-03:002015-11-28T22:07:30.949-03:00Uma brincadeira rápida<div style="text-align: justify;">
<img alt="" src="http://photos1.blogger.com/blogger/6505/3295/200/python.png" style="border: none; cursor: crosshair; float: left; margin: 0pt 10px 10px 0pt;" /><br /><br />
Um jeito divertido de calcular <a href="http://pt.wikipedia.org/wiki/Sequência_de_Fibonacci">Fibonacci</a> usando <a href="http://www.numpy.org">NumPy</a>:<br /><br />
</div>
<pre><code class="prettyprint">from collections.abc import Callable
from numpy import matrix, long
def fib() -> Callable:
m = matrix('1, 1; 1, 0', dtype=long)
def fib(n: int) -> long:
return (m ** n)[0, 0]
return fib
fib = fib()
</code></pre>
<br />
<h3>Cython</h3>
<pre><code class="prettyprint">from libc.stdint cimport int64_t
from numpy cimport ndarray
from numpy import matrix, long
cdef:
ndarray m = matrix('1, 1; 1, 0', dtype=long)
cpdef int64_t fib(int n):
return (m ** n)[0, 0]
</code></pre>
<br/>
[]’s<br />
<br />
<blockquote><tt>[update 2015-11-28]</tt><br/>
Código atualizado para Python 3 e versão Cython.<br/>
<tt>[/update]</tt></blockquote>ℭacilhας, ℒa ℬatalemahttp://www.blogger.com/profile/14265747724618147106noreply@blogger.com0tag:blogger.com,1999:blog-1387996720436450649.post-21828267258658225262015-03-29T13:00:00.001-03:002015-03-30T23:22:48.479-03:00Gxref<div style="text-align: justify;">
<img alt="Glider" src="http://2.bp.blogspot.com/_rGfO7DAuOSE/SwSZGIY_eXI/AAAAAAAAATA/Gh-qDqdTMX0/s200/glider.png" style="border: none; cursor: crosshair; float: left; height: 55px; margin: 0 10px 10px 0; width: 55px;" /><br/>
Estou experimentando o ambiente <a href="http://www.swi-prolog.org/pldoc/man?predicate=gxref/0"><code>gxref</code></a>, parte do <a href="http://www.swi-prolog.org/packages/xpce/">XPCE</a> do <a href="http://www.swi-prolog.org/">SWI-Prolog</a>, e tenho algumas impressões para compartilhar.
</div>
<br/><br/>
<h3>Editor de texto</h3>
<div style="text-align: justify;">
O editor de texto, <a href="http://www.swi-prolog.org/pldoc/man?section=pceemacs">PceEmacs</a>, é <strong>muito ruim</strong>. Baseado n<del>a porcaria d</del>o <a href="https://www.gnu.org/software/emacs/">Emacs</a>, possui comandos muito verborrágicos, é dolorosamente dependente do <em>mouse</em> e o <em>search-replace</em> é uma bosta.<br/>
<br/>
Para quem está acostumado com o <a href="http://www.vim.org/">Vim</a>, de comando curtos e eficientes, que não precisa do <em>mouse</em> pra <strong>nada</strong> – você não precisa tirar a mão do teclado enquanto edita –, o PceEmacs é um retorno às cavernas.<br/>
<br/>
A única vantagem é que o <em>syntax highlight</em> é bastante eficiente.
</div>
<div class="separator" style="clear: both; text-align: center;"><img style="border: none; cursor: crosshair;" src="http://1.bp.blogspot.com/-18EB6vBnNd0/VRghX5E3YKI/AAAAAAAABYc/Ytpn3MKfQ2A/s320/editor.jpg" /></div>
<h3><em>File info</em></h3>
<div style="text-align: justify;">
A aba <em>File info</em> é simplesmente <strong>maravilhosa</strong>! Relaciona todos os predicados, onde eles são usados e que predicados de outros módulos são usados no módulo atual.<br/>
<br/>
É uma ferramenta caída dos céus para depurar erros de sintaxe e até mesmo de lógica.
</div>
<div class="separator" style="clear: both; text-align: center;"><img style="border: none; cursor: crosshair;" src="http://4.bp.blogspot.com/-eqEjw0D6coQ/VRggBodVHjI/AAAAAAAABYI/L1W0g4lthuM/s320/file-info.jpg" /></div>
<h3><em>Dependencies</em></h3>
<div style="text-align: justify;">
A aba <em>Dependencies</em> exibe um grafo das relações entre os módulos que deixa muito claro como sua imagem se comporta.
</div>
<div class="separator" style="clear: both; text-align: center;"><img style="border: none; cursor: crosshair;" src="http://2.bp.blogspot.com/-WDI8hhUG2Hs/VRggg0B6YRI/AAAAAAAABYQ/ajnHCyxOVIQ/s320/dependencies.jpg" /></div>
<h3>Conclusão</h3>
<div style="text-align: justify;">
O XPCE+<code>gxref</code> perde pontos pelo editor de texto ruim e por depender do <a href="http://www.x.org/wiki/">X</a> (não roda nativo no Mac OS X), mas todo o resto é muito eficiente, merecendo uma nota, de zero a dez, oito (8).
</div>
<br />
[]’s<br />
ℭacilhας, ℒa ℬatalemaℭacilhας, ℒa ℬatalemahttp://www.blogger.com/profile/14265747724618147106noreply@blogger.com0tag:blogger.com,1999:blog-1387996720436450649.post-59076338439207402952014-10-07T15:21:00.002-03:002014-10-07T15:21:48.313-03:00Inception<pre><code>4525295943286785564630898738613180402752865746514908141289658206399306834966472673922031069344230677865113693205407878709601660268</code></pre>
[]’sℭacilhας, ℒa ℬatalemahttp://www.blogger.com/profile/14265747724618147106noreply@blogger.com0tag:blogger.com,1999:blog-1387996720436450649.post-53516003884348457212014-08-24T21:55:00.000-03:002014-09-24T17:22:17.379-03:00Combinador de ponto fixo<div style="text-align: justify;">
<img alt="Glider" src="http://2.bp.blogspot.com/_rGfO7DAuOSE/SwSZGIY_eXI/AAAAAAAAATA/Gh-qDqdTMX0/s200/glider.png" style="border: none; cursor: crosshair; float: left; height: 55px; margin: 0 10px 10px 0; width: 55px;" />
A beleza da matemática e do cálculo é que algo não precisa ter uma aplicação prática imediata para ser estudado em profundidade. A aplicabilidade pode surgir 150, 200 anos após sua concepção.<br />
<br />
Um dos tópicos mais magníficos do <a href="http://pt.wikipedia.org/wiki/C%C3%A1lculo_lambda">cálculo-λ</a> é o combinador de ponto fixo, apesar de ser de interesse mais acadêmico do que diretamente prático.<br />
<br />
Ainda assim, seu entendimento engrandece em tamanha proporção o conhecimento do programador, que vale a pela dedicar-lhe algum tempo.<br />
<br />
<h3>
Conceitos básicos</h3>
Há alguns pré-requisitos que você precisa conhecer para começar nosso estudo:<br />
<br />
<b>Cálculo-λ</b><br />
<br />
Cálculo-λ é uma parte da lógica matemática criada da década de 1930 como parte da investigação dos fundamentos da matemática. No cálculo-λ, todos os elementos são funções de primeira classe, inclusive os números.<br />
<br />
Por exemplo, o número 2 é uma função que aplica uma outra função duas vezes, e é representado como <code>λsz.s(sz)</code>.<br />
<br />
O sinal + (ou <code>S</code> em alguns textos) significa incremento, e é descrito como <code>λwyx.y(wyx)</code>. Ou seja, +3 é 3 incrementado, que é igual a 4. 2+3 é a função 2 recebendo como parâmetros + e 3, ou seja, incrementa duas vezes o número 3, +(+3), o que resulta em 5.<br />
<br />
A multiplicação é prefixal, não mesoclítica, ou seja, 2x escreve-se como <code>*2x</code> (ou <code>M2x</code>) e sua definição é <code>λab.a(b+)0</code> ou <code>λxyz.x(yz)</code>.<br />
<br />
O cálculo-λ é o princípio de onde deriva a <a href="http://pt.wikipedia.org/wiki/Programa%C3%A7%C3%A3o_funcional">programação funcional</a>.<br />
<br />
<blockquote>
<tt>[update 2014-08-25]</tt><br />
A definição de decremento é (caso eu não tenha copiado errado):
<br />
<pre><code>DEC = λnfx.n (λgh.h(gf)) (λu.x) I</code></pre>
<tt>[/update]</tt></blockquote>
<br />
<b>Ponto fixo</b><br />
<br />
Impossível entender combinador de ponto fixo sem saber o que significa ponto fixo. Ponto fixo é o ponto de uma função onde o valor retornado é igual ao valor fornecido.<br />
<br />
Por exemplo, dada a função f(x) = 2x-1, o que em notação cálculo-λ fica <code>f = λx.DEC(*2x)</code>, o ponto fixo é aquele onde <code>fx = x</code>, ou seja, o resultado é igual ao parâmetro.<br />
<br />
Usando aritmética básica:<br />
<pre>f(x) = 2x - 1
x = 2x - 1
2x - 1 = x
2x - 1 - x = 0
x - 1 = 0
x = 1</pre>
<br />
Portanto o ponto fixo de <code>λx.DEC(*2x)</code> é 1.<br />
<br />
Repare que a recursão sobre o ponto fixo resulta sempre no mesmo resultado. Se:<br />
<pre><code>x = fx</code></pre>
<br />
Podemos substituir <code>x</code> por <code>fx</code>:<br />
<pre><code>x = fx = f(fx) = f(f(fx))) = ...</code></pre>
<br />
<br />
<b>Variáveis livres e vinculadas</b><br />
<br />
Em cálculo-λ, no corpo de uma função, todas as variáveis que vêm de sua assinatura são vinculadas e as que vêm de fora são livres.<br />
<br />
Por exemplo, na função:<br />
<pre><code>λfx.Δxf</code></pre>
<br />
<br />
As variáveis <code>x</code> e <code>f</code> são vinculadas e a variável <code>Δ</code> é livre.<br />
<br />
<b>Combinadores</b><br />
<br />
Combinadores são funções que não possuem variáveis livres. Por exemplo:<br />
<pre><code>λx.xx
λx.y</code></pre>
<br />
A primeira linha é um combinador, já a segunda <b>não</b>.<br />
<br />
Veja que, a rigor, números e operadores aritméticos são variáveis livres, porém, como são valores constantes e bem definidos, tratam-se de exceções aceitáveis em um combinador.<br />
<br />
<b>Construção <i>let</i></b><br />
<br />
A construção <i>let</i> é uma construção clássica em cálculo-λ e em linguagens funcionais de programação.<br />
<br />
Darei um exemplo: seja <code>fx</code> igual a <code>*2x</code> em <code>f4</code>, o resultado é 8 – <code>fx</code> é o dobro e <code>x</code> e o caso é <code>f4</code>. Isso é descrito assim:<br />
<pre><code>let fx = *2x in f4</code></pre>
<br />
Podemos construir uma função assim, por exemplo, dado o parâmetro <code>x</code>, sendo <code>fa</code> igual a <code>*2a</code> em <code>fx-1</code>:<br />
<pre><code>λx.let fa = *2a in DEC(fx)</code></pre>
<br />
É o mesmo que:<br />
<pre><code>λx.DEC(*2x)</code></pre>
<br />
Em <a href="http://www.haskell.org/">Haskell</a> isso pode ser escrito assim:<br />
<pre><code class="prettyprint">func x = let f a = 2 * a in f x - 1</code></pre>
<br />
Em <a href="http://racket-lang.org/">Racket</a> fica assim:<br />
<pre><code>(describe func
(λ (x)
(let ((f (λ (a) (* 2 a)))
(- (f x) 1))))</code></pre>
<br />
A forma genérica da construção <i>let</i> é:<br />
<pre><code>let fx = y in z</code></pre>
<br />
E sua abertura é:<br />
<pre><code>(λf.z)(λx.y)</code></pre>
<br />
<br />
<h3>
Finalmente: o combinador de ponto fixo</h3>
Combinador de ponto fixo é uma função que retorna o ponto fixo da função fornecida como parâmetro. Em cálculo e mesmo em programação isso é muito útil na implementação de funções recursivas.<br />
<br />
Função recursiva é aquela que faz chamada a ela mesma, por exemplo, fatorial:<br />
<pre><code>FACT = λn.(ISZERO n) 1 (*n (FACT (DEC n)))</code></pre>
<br />
Olhando para o corpo da função, mesmo desconsiderando números e operadores (<code>ISZERO</code>, <code>1</code>, <code>*</code> e <code>DEC</code>), ainda há a variável livre <code>FACT</code>, que não é definida na assinatura da função.<br />
<br />
<blockquote>
<tt>[update 2014-08-25]</tt><br />
A definição de <code>ISZERO</code> é:
<br />
<pre><code>TRUE = λxy.x
FALSE = λxy.y
ISZERO = λn.n(λx.FALSE)TRUE</code></pre>
<tt>[/update]</tt></blockquote>
<br />
A forma de resolver isso é criar uma função que recebe a si mesma na assinatura:<br />
<pre><code>ALMOST-FACT = λfn.(ISZERO n) 1 (*n (f (DEC n)))</code></pre>
<br />
Quando esse combinador recebe como parâmetro o fatorial, ele retorna o próprio fatorial, assim a função fatorial é o <b>ponto fixo</b> dele!<br />
<br />
O combinador de ponto fixo é aquele que, ao receber a função como parâmetro, retorna seu ponto fixo – e quando a função recebe o ponto fixo, retorna o próprio ponto fixo, segundo o seguinte comportamento:<br />
<pre><code>yf = f(yf)</code></pre>
<br />
Só aqui já seria possível implementar uma função que calcule o ponto fixo. Em Haskell:<br />
<pre><code class="prettyprint">fix f = f (fix f)</code></pre>
<br />
E em <a href="http://docs.racket-lang.org/lazy/">Lazy Racket</a>:<br />
<pre><code>(define fix
(λ (f)
(f (fix f))))</code></pre>
<br />
Porém seria sem sentido, pois essa mesma função que resolve o problema, é parte do problema, já que ela própria possui variável livre.<br />
<br />
Resolver este problema não é difícil: basta pegarmos a definição: dada uma função <code>f</code>, queremos o ponto <code>x</code> onde <code>fx</code> seja igual a <code>x</code>… é uma construção <i>let</i>!<br />
<br />
Data uma função que recebe <code>f</code> (<code>λf.</code>), seja <code>x</code> igual a <code>fx</code> (<code>let x = fx</code>) em <code>x</code> (<code>in x</code>):<br />
<pre><code>λf.let x = fx in x</code></pre>
<br />
De fato isso já funciona em Haskell:<br />
<pre><code class="prettyprint">fix :: (a -> a) -> a
fix f = let x = f x in x</code></pre>
<br />
<br />
<h3>
Combinador Y</h3>
Para Scheme (Lazy Racket), precisamos destrinchar um pouco mais, abrindo o <i>let</i>.<br />
<br />
Precisamos de dois parâmetros na primeira posição, portanto dobraremos o <code>x</code>:<br />
<pre><code>λf.let x = fx in x
λf.let xx = f(xx) in xx
λf.(λx.xx)(λx.f(xx))</code></pre>
<br />
Mais um passo e chegamos ao famoso <a href="https://mvanier.livejournal.com/2897.html">combinador Y</a> de <a href="http://pt.wikipedia.org/wiki/Haskell_Curry">Curry</a>!<br />
<br />
Aplicando o parâmetro <code>λx.f(xx)</code> à função <code>λx.xx</code>, temos <code>(λx.f(xx))(λx.f(xx))</code>, exatamente o combinador Y de Curry:<br />
<pre><code>Y = λf.(λx.f(xx))(λx.f(xx))</code></pre>
<br />
Em Lazy Racket:<br />
<pre><code>(define Y
(λ (f)
((λ (x) (f (x x))) (λ (x) (f (x x))))))</code></pre>
<br />
<br />
<h3>
Linguagens estritas</h3>
A maioria das linguagens não suporta <i>lazy evaluation</i>, então é preciso fazer um truque para que a definição do combinador não entre em <i>loop</i> infinito.<br />
<br />
O truque é aplicar a função <code>λsv.sv</code> (que é o número 1, equivalente à identidade: <code>I = λx.x</code>). Por exemplo:<br />
<pre><code>g = 1g
g = (λsv.sv) g
g = (λv.gv)</code></pre>
<br />
Por exemplo, o combinador Y em <a href="https://www.python.org/">Python</a>:<br />
<pre><code class="prettyprint">Y = lambda f: (lambda x: x(x))(lambda x: f(x(x)))</code></pre>
<br />
Esse código entra em <b><i>loop</i> infinito</b>! Mas se substituirmos <code>xx</code> por <code>λv.xxv</code>, tudo se resolve:<br />
<pre><code class="prettyprint">Y = lambda f: (lambda x: x(x))(lambda x: f(lambda *args: x(x)(*args)))</code></pre>
<br />
<br />
<h3>
Outros combinadores de ponto fixo</h3>
Curry foi o que obteve a solução mais simples para o combinador de ponto fixo, mas não foi o único. Há outras soluções possíveis.<br />
<br />
<b>Combinador de <a href="http://pt.wikipedia.org/wiki/Alan_Turing">Turing</a>:</b><br />
<pre><code>Θ = (λx.xx)(λab.b(aab))</code></pre>
<br />
<br />
<b>Combinador de ponto fixo estrito (vimos acima):</b><br />
<pre><code>Z = λf.(λx.xx)(λx.f(λv.xxv))</code></pre>
<br />
<b>Combinador de ponto fixo não padrão:</b><br />
<pre><code>B = λwyx.w(yx)
∆ = λx.xx
N = B∆(B(B ∆)B)</code></pre>
<br /></div>
[]’sℭacilhας, ℒa ℬatalemahttp://www.blogger.com/profile/14265747724618147106noreply@blogger.com0tag:blogger.com,1999:blog-1387996720436450649.post-85353436664346888302014-05-24T19:58:00.001-03:002014-05-26T16:16:01.674-03:00Erlang vs Prolog<div style="text-align: justify;">
<img alt="Poliedro" src="http://photos1.blogger.com/blogger/6505/3295/200/prog.png" style="border: medium none; cursor: crosshair; float: left; margin: 0pt 10px 10px 0pt;" /><br />
<br />
<del>Simon Thompson</del> <a href="http://joearms.github.io/">Joe Armstrong</a> criou <a href="http://www.erlang.org/">Erlang</a> a partir de <a href="http://pt.wikipedia.org/wiki/Prolog">Prolog</a> – aliás, o primeiro compilador era escrito <b>em</b> Prolog.<br />
<br />
</div>
<blockquote><div style="text-align: justify;">
<tt>[update 2014-05-25]</tt><br />
<i>Faglia nostra</i>: o programador Prolog e criador da linguagem Erlang é <a href="http://joearms.github.io/">Joe Armstrong</a>. <a href="http://www.oreilly.com/pub/au/3534">Simon Thompson</a> é o mantenedor e um dos resposáveis pela reescrita em C.<br />
<tt>[/update]</tt></div></blockquote>
<div style="text-align: justify;">
Apesar de ser uma linguagem funcional, Erlang traz muita herança de Prolog e suporta o paradigma declarativo. Para demonstrar essa similaridade, vou colocar o código de <a href="http://pt.wikipedia.org/wiki/Fatorial">fatorial</a>: em Erlang e em Prolog, implementação simples (e ruim) e usando <i>tail-call optimization</i>.</div>
<br />
<h3>
Código Q&D</h3>
<div style="text-align: justify;">
Vamos ao rápido e sujo, primeiro em Prolog:
</div>
<br />
<pre><code class="prettyprint">fact(0, 1) :- !.
fact(N, F) :- N > 0,
N1 is N - 1,
fact(N1, F1),
F is N * F1.</code></pre>
<br />
<div style="text-align: justify;">
Agora em Erlang:
</div>
<br />
<pre><code class="prettyprint">fact(0) -> 1;
fact(N) when N > 1 -> N * fact(N - 1).</code></pre>
<br />
<div style="text-align: justify;">
A intenção é mostrar como os códigos são parecidos.
</div>
<br />
<h3>
<i>Tail call optimization</i></h3>
<div style="text-align: justify;">
Tanto Prolog quanto Erlang têm sistemas inteligentes de esvaziamento de pilha e usar um acumulador ajuda a tornar o programa mais eficiente.<br />
<br />
O fatorial em Prolog fica assim:
</div>
<br />
<pre><code class="prettyprint">fact(N, F) :- N >= 0,
fact(N, 1, F).
fact(0, F, F) :- !.
fact(N, A, F) :- N1 is N - 1,
A1 is N * A,
fact(N1, A1, F).
</code></pre>
<br />
<div style="text-align: justify;">
Agora em Erlang:
</div>
<br />
<pre><code class="prettyprint">fact(N) when N >= 0 -> fact(N, 1).
fact(0, A) -> A;
fact(N, A) -> fact(N-1, A*N).</code></pre>
<br />
<h3>
Bônus</h3>
<div style="text-align: justify;">
Tente adivinhar em qual linguagem é este código:
</div>
<br />
<pre><code class="prettyprint">fact(N, F) :- N >= 0, fact(N, 1, F).
fact(0) --> { ! }, '='.
fact(N) --> { N1 is N - 1 }, mul(N), fact(N1).
mul(N, A, R) :- R is N * A.</code></pre>
<br />
<br />
[]’s<br />
ℭacilhας, ℒa ℬatalemaℭacilhας, ℒa ℬatalemahttp://www.blogger.com/profile/14265747724618147106noreply@blogger.com0tag:blogger.com,1999:blog-1387996720436450649.post-66541730511233118562014-05-19T09:46:00.001-03:002014-05-26T16:46:43.017-03:00PL Framework<div style="text-align: justify;">
<img alt="Glider" src="http://2.bp.blogspot.com/_rGfO7DAuOSE/SwSZGIY_eXI/AAAAAAAAATA/Gh-qDqdTMX0/s200/glider.png" style="border: none; cursor: crosshair; float: left; height: 55px; margin: 0 10px 10px 0; width: 55px;" /><br/>
Falei sobre <a href="http://kodumaro.blogspot.com.br/2014/05/dados-em-prolog.html">como gerenciar dados mutáveis</a> em <a href="http://www.swi-prolog.org/">Prolog</a>. O código final ficou assim:
</div>
<br />
<br />
<pre><code class="prettyprint">-*- Prolog -*-
:- module(profile, [profile/2]).
:- dynamic profile/2.
set(ID, X) :- profile(ID, X), !.
set(ID, X) :- X =.. [Attr, _],
E =.. [Attr, _],
retractall(profile(ID, E)),
assertz(profile(ID, X)), !.
set(_, []) :- !.
set(ID, [X|Rest]) :- set(ID, X), set(ID, Rest).
get(ID, R) :- findall(X, profile(ID, X), R).
drop(ID) :- retractall(profile(ID, _)).</code></pre>
<br />
<div style="text-align: justify;">
Mas e se quisermos que os dados sejam persistentes, ou seja, sobrevivam entre execuções, como um banco de dados?<br />
<br />
O dialeto SWI Prolog oferece um arcabouço com inúmeros recursos chamado <a href="http://www.swi-prolog.org/FAQ/PrologLAMP.txt">PL Framework</a>.<br />
<br />
Para persistência, há a biblioteca <a href="http://www.swi-prolog.org/pldoc/doc/swi/library/persistency.pl"><code>persistency.pl</code></a>.<br />
<br />
O que temos de fazer é substituir algumas partes de nosso código pelos predicados da biblioteca. Começaremos importando o módulo: logo após a declaração do nosso módulo, na linha abaixo, acrescente a importação:
</div>
<pre><code class="prettyprint">:- use_module(library(persistency)).</code></pre>
<br />
<div style="text-align: justify;">
Em seguida, não precisamos mais declarar o predicado <code>profile/2</code> como dinâmico, em vez disso vamos declarar uma persistência. Substituia a linha com <code>dynamic</code> por:
</div>
<pre><code class="prettyprint">:- persistent profile(id:atom, attr:compound).</code></pre>
<br />
<div style="text-align: justify;">
Agora precisamos subtituir as chamadas de <code>retractall/1</code> por <code>retractall_profile/2</code>, protegidas por <code>with_mutex/2</code>.<br />
<br />
Onde está:
</div>
<pre><code class="prettyprint"> retractall(profile(ID, E)),</code></pre>
<br />
<div style="text-align: justify;">
Substitua por:
</div>
<pre><code class="prettyprint"> with_mutex(profile,
retractall_profile(ID, E)),</code></pre>
<br />
<div style="text-align: justify;">
E substitua:
</div>
<pre><code class="prettyprint">drop(ID) :- retractall(profile(ID, _)).</code></pre>
<br />
<div style="text-align: justify;">
Por:
</div>
<pre><code class="prettyprint">drop(ID) :- with_mutex(profile,
retractall_profile(ID, _)).</code></pre>
<br />
<div style="text-align: justify;">
Agora precisamos substituir <code>assertz/1</code> por <code>assert_profile/2</code>. Onde está:
</div>
<pre><code class="prettyprint"> assertz(profile(ID, X)), !.</code></pre>
<br />
<div style="text-align: justify;">
Substitua por:
</div>
<pre><code class="prettyprint"> with_mutex(profile,
assert_profile(ID, X)), !.</code></pre>
<br />
<div style="text-align: justify;">
Você pode juntar os predicados dentro de <code>with_mutex/2</code>.<br />
<br />
Precisamos agora de uma regra para conectar a uma base de dados em disco, por exemplo:
</div>
<pre><code class="prettyprint">connect(File) :- db_attach(File, [gc]).</code></pre>
<br />
<div style="text-align: justify;">
Se quiser um arquivo padrão:
</div>
<pre><code class="prettyprint">connect :- connect('profile.db').</code></pre>
<br />
<h3>
Código final com persistência</h3>
<pre><code class="prettyprint">-*- Prolog -*-
:- module(profile, [profile/2]).
:- persistent profile(id:atom, attr:compound).
set(ID, X) :- profile(ID, X), !.
set(ID, X) :- X =.. [Attr, _],
E =.. [Attr, _],
with_mutex(profile,
(retractall_profile(ID, E),
assert_profile(ID, X))), !.
set(_, []) :- !.
set(ID, [X|Rest]) :- set(ID, X), set(ID, Rest).
get(ID, R) :- findall(X, profile(ID, X), R).
drop(ID) :- with_mutex(profile,
retractall_profile(ID, _)).
connect :- connect('profile.db').
connect(File) :- db_attach(File, [gc]).</code></pre>
<br />
<div style="text-align: justify;">
Este artigo foi apenas um exemplo prático de Prolog.
</div>
<br />
[]’s<br />
ℭacilhας, ℒa ℬatalemaℭacilhας, ℒa ℬatalemahttp://www.blogger.com/profile/14265747724618147106noreply@blogger.com0tag:blogger.com,1999:blog-1387996720436450649.post-61816833967328703232014-05-17T10:13:00.007-03:002014-05-25T16:52:04.946-03:00Pequeno glossário de Prolog<div style="text-align: justify;">
<img alt="Glider" src="http://2.bp.blogspot.com/_rGfO7DAuOSE/SwSZGIY_eXI/AAAAAAAAATA/Gh-qDqdTMX0/s200/glider.png" style="border: none; cursor: crosshair; float: left; height: 55px; margin: 0 10px 10px 0; width: 55px;" /> Ontem eu escrevi um <a href="http://kodumaro.blogspot.com.br/2014/05/dados-em-prolog.html">artigo simples</a> sobre <a href="http://www.swi-prolog.org/">Prolog</a>.<br />
<br />
O artigo na <a href="http://pt.wikipedia.org/wiki/Prolog">Wikipédia em português</a> me pareceu pouco completo e bastante confuso. Tem informações legais lá, mas em comparação com a <a href="http://en.wikipedia.org/wiki/Prolog">versão em inglês</a> deixa a desejar.<br />
<br />
Não pretendo completar o que está escrito na Wikipédia (senão deveria completar lá), apenas descomplicar um pouco.<br />
<br />
Pra começar, é preciso entender a estrutura de um programa em Prolog: consiste em um domínio de verdades, parecido com uma base de dados, e o ponto de entrada é uma pergunta (<i>query</i>). Dito isso, vamos definir os conceitos dentro do código:
<br />
<ul>
<li><b>Termo</b>: qualquer dado em Prolog é chamado termo.</li>
<li><b>Átomo</b>: é um nome de propósito geral sem significado inerente. É representado por uma sequência de letras e alguns caracteres, começando por uma letra minúscula, ou qualquer sequência entre piclas (<code>'…'</code>). Por exemplo: <code>hanoi</code></li>
<li><b>Número</b>: pode ser inteiro ou de ponto flutuante, não diferente de outras linguagens.</li>
<li><b>Termo composto</b>: consiste em um átomo, chamado <b><i>functor</i></b> (que é uma cabeça ou cabeçalho) seguido de uma sequência de termos e/ou incógnitas separados por vírgulas e entre parêntesis, chamada argumentos. Por exemplo: <code>hanoi(5, R)</code></li>
<li><b>Predicado</b>: é uma <a href="http://pt.wikipedia.org/wiki/Predicado_(l%C3%B3gica_matem%C3%A1tica)">função booleana</a>, ou seja, que retorna verdadeiro ou falso. Um predicado pode ser um átomo ou um termo composto e deve ser definido por um fato ou por uma regra.</li>
<li><b>Operador</b>: é um predicado normal de aridade 2, mas que pode ser representado de forma diferente. Por exemplo, o sinal de igual:</li>
</ul>
</div>
<pre><code class="prettyprint">X = 2</code></pre>
<br />
<div style="text-align: justify;">
É o mesmo que:
</div>
<pre><code class="prettyprint">'='(X, 2)</code></pre>
<br />
<div style="text-align: justify;">
<ul>
<li><b>Variável</b>: prefiro evitar a expressão “variável”, pois ela é falsa, apesar de ser o nome oficial. Prefiro “<b>incógnita</b>”: a incógnita pode estar ligada (<i>bound</i>) ou não (<i>unbound</i>) a um termo e tem comportamento diferente de acordo com estar ou não ligada. É representada por uma sequência de letras iniciando por uma letra maiúscula ou um <i>underscore</i> (<code>_</code>). Por exemplo: <code>X</code></li>
<li><b>Fato</b>: indica que determinado predicado retorna verdadeiro. É um átomo ou termo composto seguido de um ponto. Por exemplo:</li>
</ul>
</div>
<pre><code class="prettyprint">default(5).</code></pre>
<br />
<div style="text-align: justify;">
<ul>
<li><b>Regra</b>: condiciona o resultado de um predicado ao resultado de outro. É um átomo ou termo seguido de <code>:-</code> e então o predicado ao qual ele está condicionado. Por exemplo:.</li>
</ul>
</div>
<pre><code class="prettyprint">move(_, X, Y, _, R) :- move(1, X, Y, _, R).</code></pre>
<br />
<div style="text-align: justify;">
<ul>
<li><b>Pergunta</b> (<b><i>query</i></b>): É a chamada de um predicado. Pode retornar verdadeiro, falso ou gerar uma exceção. No código, é uma linha iniciada por <code>:-</code> e terminada por ponto. No <i>prompt</i> <code>?-</code> basta digitar o predicado seguido de um ponto e pressionar a tecla <i>Enter</i>.</li>
</ul>
<br />
Um detalhe importante é que coisas que não parecem predicados, também são! Por exemplo:
<br />
<ul>
<li><b>Vírgula</b>: é operador (<code>','/2</code>) que avalia o primeiro um predicado (argumento) e só avalia o segundo se o primeiro for verdadeiro, ou seja, <b>E lógico</b>.</li>
</ul>
</div>
<pre><code class="prettyprint">N1 is N - 1, fact(N1, F1)</code></pre>
<br />
<div style="text-align: justify;">
<ul>
<li><b>Ponto e vírgula</b>: operador (<code>';'/2</code>) que avalia o primeiro predicado e só avalia o segundo se o primeiro for falso, ou seja, <b>OU lógico</b>.</li>
<li><b>Exclamação</b>: é um predicado de aridade 0 (<code>'!'/0</code>) que indica que, se a regra atual “casar” (<em>match</em>) com a pergunta, os próximos fatos ou regras não serão avaliados.</li>
<li>Qualquer operação matemática.</li>
</ul>
<br />
Como exemplo, segue uma implementação da resolução da torre de Hanói:
</div>
<pre><code class="prettyprint">% -*- Prolog -*-
:- module(hanoi, [hanoi/0, hanoi/1, hanoi/2]).
hanoi :- hanoi(R), findall(_, show(R), _).
hanoi(R) :- default(N), hanoi(N, R).
hanoi(N, R) :- N > 0,
findall(X,
move(N,
'a esquerda',
'a direita',
'o centro', X),
R).
default(5).
move(1, X, Y, _, move(X, Y)) :- !.
move(N, X, Y, Z, R) :- N1 is N - 1, move(N1, X, Z, Y, R).
move(_, X, Y, _, R) :- move(1, X, Y, _, R).
move(N, X, Y, Z, R) :- N1 is N - 1, move(N1, Z, Y, X, R).
show(move(X, Y)) :- format('mova o disco d~w para ~w~n', [X, Y]).
show([X|_]) :- show(X).
show([_|Rest]) :- show(Rest).
</code></pre>
<br />
<div style="text-align: justify;">
Consegue entender como funciona?<br />
<br />
Para gerar um executável com SWI Prolog:
</div>
<pre><code>bash$ <b>prolog -f hanoi.pl \</b>
<b>-g 'use_module(library(save)), qsave_program(hanoi, [goal(hanoi)])' \</b>
<b>-t halt</b></code></pre>
<br />
<h3>
Bônus</h3>
<div style="text-align: justify;">
Há um açúcar sintático em prolog, que é <code>--></code>:
</div>
<pre><code class="prettyprint">a --> b, c(x), d.</code></pre>
<br />
<div style="text-align: justify;">
Significa o mesmo que:
</div>
<pre><code class="prettyprint">a(Start, End) :- b(Start, V1), c(x, V1, V2), d(V2, End).</code></pre>
<br />
[]’s<br />
ℭacilhας, ℒa ℬatalemaℭacilhας, ℒa ℬatalemahttp://www.blogger.com/profile/14265747724618147106noreply@blogger.com0tag:blogger.com,1999:blog-1387996720436450649.post-45013737483490943712014-05-17T00:20:00.003-03:002014-05-25T16:52:20.462-03:00Dados em Prolog<div style="text-align: justify;">
<img alt="Glider" src="http://2.bp.blogspot.com/_rGfO7DAuOSE/SwSZGIY_eXI/AAAAAAAAATA/Gh-qDqdTMX0/s200/glider.png" style="border: none; cursor: crosshair; float: left; height: 55px; margin: 0 10px 10px 0; width: 55px;" /> Há uns anos falei um <a href="http://kodumaro.blogspot.com.br/2011/07/prolog.html">pouquinho</a> sobre <a href="http://pt.wikipedia.org/wiki/Prolog">Prolog</a>: sobre predicados, átomos, termos compostos, fatos, regras, incógnitas, etc.<br />
<br />
Só pra relembrar: um programa em Prolog é um conjunto de predicados – fatos e regras – e sua execução consistem em perguntas (<i>queries</i>) feitas a esse domínio de verdades. Na programação declarativa, a ideia não é dizer como o computador deve resolver o problema, mas sim descrever o problema.<br />
<br />
O entendimento de Prolog é essencial ao entendimento da programação declarativa e, assim, para poder extrair o máximo do poder de linguagens mais modernas, como <a href="http://www.erlang.org/">Erlang</a>.<br />
<br />
É uma história bonita, mas um exemplo um pouco mais prático iria bem, não?<br />
<br />
Então imaginei um exemplo: um módulo que representa perfis de dados – por exemplo, dados de perfil de usuário.<br />
<br />
Podemos começar o código dizendo para o sistema nosso módulo:
</div>
<pre><code class="prettyprint">% -*- Prolog -*-
:- module(profile, [profile/2]).</code></pre>
<br />
<div style="text-align: justify;">
A primeira linha é um comentário que avisa a alguns editores que o arquivo se trata de um código Prolog, a segunda declara o módulo <code>profile</code>, que exporta o predicado <code>profile/2</code> (com aridade 2).<br />
<br />
A seguir, podemos declarar nosso predicado <code>profile/2</code>:
</div>
<pre><code class="prettyprint">:- dynamic profile/2.</code></pre>
<br />
<div style="text-align: justify;">
Essa declaração diz que o predicado <code>profile/2</code> é dinâmico, ou seja, muda ao longo da execução do programa.<br />
<br />
Agora precisamos de um predicado para gravar novos dados de perfil. Façamos isso com uma regra:
</div>
<pre><code class="prettyprint">set(ID, X) :- profile(ID, X), !.</code></pre>
<br />
<div style="text-align: justify;">
Essa regra diz ao sistema que, se alguém questionar <code>set(ID, X)</code> – onde <code>ID</code> é o identificador do perfil e <code>X</code> é um atributo do perfil – e essa combinação for verdadeira, ele não deve assumir isso como ver dade e não avaliar demais regras ou fato (<code>!</code>).<br />
<br />
A próxima regra é um pouco longa, então vou falar dela linha a linha:
</div>
<pre><code class="prettyprint">set(ID, X) :- X =.. [Attr, _],</code></pre>
<br />
<div style="text-align: justify;">
Aqui diz que o predicado é <code>set(ID, X)</code> (exatamente igual ao anterior), e <code>X</code> é um termo composto de aridade 1, cujo cabeçalho será atrelado à incógnita <code>Attr</code>.<br />
<br />
Caso verdade, continua a próxima linha da regra:
</div>
<pre><code class="prettyprint"> E =.. [Attr, _],</code></pre>
<br />
<div style="text-align: justify;">
Então <code>E</code> é termo composto com mesmo cabeçalho e aridade de <code>X</code>, porém com parâmetro <code>_</code>, que significa qualquer coisa.<br />
<br />
Então, se <code>X</code> for <code>name(john)</code>, <code>E</code> será <code>name(_)</code>.
</div>
<pre><code class="prettyprint"> retractall(profile(ID, E)),</code></pre>
<br />
<div style="text-align: justify;">
Remove o predicado com o dado de perfil com o mesmo identificador e o mesmo cabeçalho informados.
</div>
<pre><code class="prettyprint"> assertz(profile(ID, X)).</code></pre>
<br />
<div style="text-align: justify;">
Cria o predicado armazenando o atributo de perfil informada – e assim termina nossa regra.<br />
<br />
E se quisermos criar uma lista de atributos para o mesmo identificador de perfil?<br />
<br />
Podemos criar um predicado para isso. Comecemos pelo ponto de parar, que é quando nossa lista de atributos já foi esgotada:
</div>
<pre><code class="prettyprint">set(_, []) :- !.</code></pre>
<br />
<div style="text-align: justify;">
Essa regra diz que, se a lista de atributos está vazia, não precisa fazer mais nada. Mas e se contiver algum elemento? Precisaremos questionar o <code>set/2</code> para aquele atributo e continuar chamando para o resto da lista:
</div>
<pre><code class="prettyprint">set(ID, [X|Rest]) :- set(ID, X), set(ID, Rest).</code></pre>
<br />
<div style="text-align: justify;">
Resolvido.<br />
<br />
Podemos criar um predicado para retornar todos os atributos de uma identidade:
</div>
<pre><code class="prettyprint">get(ID, R) :- findall(X, profile(ID, X), R).</code></pre>
<br />
<div style="text-align: justify;">
Precisamos agora de um predicado de limpeza, um para remover todos os atributos de um identificador (o que significa apagar o identificador):
</div>
<pre><code class="prettyprint">drop(ID) :- retractall(profile(ID, _)).</code></pre>
<br />
<div style="text-align: justify;">
Vamos testar agora nosso módulo:
</div>
<pre><code>?- <b>[profile].</b>
true.
?- <b>profile:set(1, [name(john), age(20), city(rio)]).</b>
true.
?- <b>profile:set(2, [name(jack), age(21), city(sao_paulo)]).</b>
true.
?- <b>profile(ID, city(City)).</b>
ID = 1
City = rio <b>;</b>
ID = 2
City = sao_paulo.
?- <b>profile:get(1, R).</b>
R = [name(john), age(20), city(rio)].
?- <b>profile:drop(1).</b>
true.
?- <b>profile(ID, _).</b>
2 <b>;</b>
2 <b>;</b>
2.
?- <b>drop(_)</b>.
true
?- <b>profile(ID, _)</b>
false.
?- </code></pre>
<br />
<div style="text-align: justify;">
Espero que o exemplo tenha sido esclarecedor. Para fazer um <i>tracing</i>, você pode fazer a pergunta <code>gtrace</code>.<br />
<br />
<b>Observação:</b> para a execução, foi usando <a href="http://www.swi-prolog.org/">SWI Prolog</a>, uma das mais confiáveis e robustas implementações de Prolog da atualidade.<br/>
<br/>
Complemento a este artigo: <a href="http://kodumaro.blogspot.com.br/2014/05/pequeno-glossario-de-prolog.html">Pequeno glossário de Prolog</a>.
</div>
<br />
[]’s<br />
ℭacilhας, ℒa ℬatalemaℭacilhας, ℒa ℬatalemahttp://www.blogger.com/profile/14265747724618147106noreply@blogger.com0tag:blogger.com,1999:blog-1387996720436450649.post-75002645481554321742014-04-12T11:42:00.002-03:002014-04-12T11:42:43.018-03:00Modelo de dados em Python<div style="text-align: justify;">
<img alt="" src="http://photos1.blogger.com/blogger/6505/3295/200/python.png" style="border: none; cursor: crosshair; float: left; margin: 0pt 10px 10px 0pt;" /> Ao escrever uma classe em <a href="https://www.python.org/">Python</a>, é preciso ficar atento a algumas convenções a serem respeitadas.<br />
<br /></div>
<h3>
Métodos especiais</h3>
<div style="text-align: justify;">
Em Python, métodos começando e terminando com sublinha dobrado (<code>__*__</code>) são reservados e chamados <b>especiais</b>. Você <b>não deve</b> implementá-los se não souber o que está fazendo.<br />
<br />
Métodos especiais podem fazer coisas maravilhosas ou criar comportamentos inesperados que <i>zoarão</i> com sua aplicação. São divididos em 12 tipos:<br />
<ol>
<li>Personalização básica;</li>
<li>Acesso personalizado a atributos;</li>
<li>Criação personalizada de classes;</li>
<li>Verificações personalizadas de instâncias e subclasses;</li>
<li>Emulação de chamada;</li>
<li>Emulação de recipiente;</li>
<li>Emulação de tipos sequenciais;</li>
<li>Emulação de tipos numéricos;</li>
<li>Regras de coerção;</li>
<li>Gerenciamento de contexto;</li>
<li>Pesquisa de classes <i>old-style</i>;</li>
<li>Pesquisa de classes <i>new-style</i>.</li>
</ol>
<br />
Recomendo fortemente a leitura do documento <a href="https://docs.python.org/2/reference/datamodel.html">Data model</a>, é <b>essencial</b> ao bom programador.<br />
<br /></div>
<h3>
Métodos privados</h3>
<div style="text-align: justify;">
Métodos privados são iniciados com sublinha dobrado, mas <b>não</b> terminados da mesma forma (<code>__*</code>).<br />
Um método privado <b>não pode</b> ser acessado de outro contexto a não ser da classe onde ele foi definido.<br />
<br />
Isso não é de todo verdade… o que acontece de fato é que métodos privados são prefixados com um sublinha seguido do nome da classe, para evitar que sejam sobrescritos e prevenir acesso a partir de subclasses ou de fora do contexto da classe.<br />
<br />
Por exemplo, no contexto da classe <code>Person</code>, todos os métodos iniciados com sublinha dobrado serão prefixados com <code>_Person</code>. Assim, <code>__fix_data</code> vira <code>_Person__fix_data</code>.<br />
<br />
Isso permite que você faça herança múltipla de classes que possuem o <i>mesmo</i> nome de método privado sem conflitos.</div>
<h3>
Métodos protegidos</h3>
<div style="text-align: justify;">
Há uma convenção em Python de que métodos com nome iniciado com um sublinha (<code>_*</code>) são protegidos, ou seja, só devem ser acessados no contexto da classe e de suas subclasses.<br />
<br />
<b>Nenhum tratamento</b> é feito para evitar que sejam acessados de outros contextos, mas se espera que os programadores sigam a convenção.<br />
<br />
A orientação em Python é que o programador não é nenhum bebezinho que precisa ser guiado e sabe o que está fazendo, portanto não aja como um bebê e respeite as convenções.<br />
<br /></div>
<h3>
Atributos e propriedades</h3>
<div style="text-align: justify;">
<b>Tudo</b> o que foi dito sobre métodos especiais, privados e protegidos <b>também vale</b> para atributos e propriedades.
</div>
<br />
[]’s<br />
Cacilhας, La Batalema ℭacilhας, ℒa ℬatalemahttp://www.blogger.com/profile/14265747724618147106noreply@blogger.com0tag:blogger.com,1999:blog-1387996720436450649.post-7999621972812584002014-04-12T09:40:00.000-03:002015-04-18T17:54:40.357-03:00Ordem de chamada dos métodos de inicialização<div style="text-align: justify;">
<img alt="" src="http://photos1.blogger.com/blogger/6505/3295/200/python.png" style="border: none; cursor: crosshair; float: left; margin: 0pt 10px 10px 0pt;" /> Quando você cria e instancia uma classe em <a href="https://www.python.org/">Python</a>, muita coisa acontece e acho que nem todos estão familiarizados com os passos.<br />
<br />
Vamos dar uma olhada na sequência.<br />
<br />
<h3>
Criação da classe</h3>
Quando você cria uma classe com o <i>statement</i> <code>class</code>, a primeira coisa que acontece é o construtor (<code>__new__</code>) da metaclasse (por padrão <code>type</code>) ser chamado.<br />
<br />
O construtor recebe como parâmetros a própria metaclasse, o nome da classe (<code>str</code>), uma tupla contendo as classes base da classe criada e um dicionário com métodos e atributos declarados no corpo da classe.<br />
<br />
Caso você sobrescreva o construtor da metaclasse, ele precisa retornar o objeto instanciado, que você obtém do construtor da classe pai da metaclasse.<br />
<br />
Em seguida o método de inicialização (<code>__init__</code>) da metaclasse é chamado, recebendo como parâmetros o retorno do construtor, o nome da classe, a tupla de classes base e o dicionário de métodos e atributos.<br />
<br />
É recomendável <b>não</b> sobrescrever o construtor da metaclasse. Qualquer procedimento pode ser tranquilamente executado nos métodos e inicialização e de chamada.<br />
<br />
<h3>
Instanciação da classe</h3>
Quando você instancia a classe, o primeiro método a ser chamado é o método de chamada (<code>__call__</code>) da metaclasse. Ele recebe como parâmetros a classe e quaisquer parâmetros passados no comando de instanciação.<br />
<br />
Em seguida é evocado o construtor da classe, recebendo a classe e quaisquer parâmetros passados no comando de instanciação.<br />
<br />
É obrigatório que a instância criada pelo construtor de <code>super</code> seja retornada, caso o construtor seja sobrescrito.<br />
<br />
Após o construtor, o método de inicialização da classe é chamado, recebendo como parâmetros o retorno do construtor e quaisquer parâmetros passados no comando de instanciação.<br />
<br />
<h3>
Chamando a instância</h3>
Caso o método de chamada seja implementado na classe, a instância é “chamável” (<i>callable</i>). Na chamada o método de chamada é executado recebendo a instância e quaisquer parâmetros passados na chamada da instância.<br />
<br />
<h3>
Quem é quem</h3>
Um pequeno código apenas com <i>boilerplates</i> que não executam nada, com o único objetivo de demonstrar onde fica cada método citado:
</div>
<pre><code class="prettyprint">class Metaclasse(type):
def __new__(meta, name, base, dict_):
""" Este é o construtor da metaclasse """
return type.__new__(meta, name, base, dict_)
def __init__(cls, name, base, dict_):
""" Este é o método de inicialização da metaclasse """
type.__init__(cls, name, base, dict_)
def __call__(cls, *args, **kwargs):
""" Este é o método de chamada da metaclasse """
return type.__call__(cls, *args, **kwargs)
class Classe(object):
__metaclass__ = Metaclasse
def __new__(cls, *args, **kwargs):
""" Este é o construtor da classe """
return super(Classe, cls).__new__(cls)
def __init__(self, *args, **kwargs):
"""
Este é o método de inicialização da classe.
Como ela herda de object, não há necessidade de
chamar super, mas quando houver, a forma é:
super(Classe, self).__init__(*args, **kwargs)
"""
def __call__(self, *args, **kwargs):
""" Este é o método de chamada da classe """
return None
</code></pre>
<br />
<blockquote><tt>[update 2015-04-18]</tt>
Esta é a versão do código acima em Python 3:<br/><pre><code class="prettyprint"><small>class Metaclasse(type):
def __new__(meta, name: str, base: tuple, dict_: dict) -> type:
""" Este é o construtor da metaclasse """
return type.__new__(meta, name, base, dict_)
def __init__(cls, name: str, base: tuple, dict_: dict):
""" Este é o método de inicialização da metaclasse """
type.__init__(cls, name, base, dict_)
def __call__(cls, *args, **kwargs) -> object:
""" Este é o método de chamada da metaclasse """
return type.__call__(cls, *args, **kwargs)
class Classe(object, metaclass=Metaclasse):
def __new__(cls, *args, **kwargs) -> object:
""" Este é o construtor da classe """
return super().__new__(cls)
def __init__(self, *args, **kwargs):
"""
Este é o método de inicialização da classe.
Como ela herda de object, não há necessidade de
chamar super, mas quando houver, a forma é:
super().__init__(*args, **kwargs)
"""
def __call__(self, *args, **kwargs) -> None:
""" Este é o método de chamada da classe """
return None</small></code></pre>
<tt>[/update]</tt></blockquote><br/>
<div style="text-align: justify;">
<h3>
Dois dedos de prosa sobre método destruidor</h3>
O método destruidor (<code>__del__</code>) <b>não é chamado</b> quando o objeto perde todas as referências ativas, mas sim quando é coletado pelo <i>garbage collector</i> (<code>gc</code>).<br />
<br />
Como o <code>gc</code> não tem hora certa para rodar e seu comportamento varia muito de uma implementação de Python para outra, não é recomendável confiar nele para executar procedimentos críticos.<br />
<br />
O que você pode fazer é usá-lo para garantir determinados estados que podem ter sido esquecidos ou perdidos depois que a instância ficou sem referências.<br />
<br />
<h3>
Observações finais</h3>
As assinaturas do construtor e do método de inicialização da classe devem ser <b>rigorosamente iguais</b>.<br />
<br />
<blockquote>
<tt>[update]</tt><br />
Um detalhe importante é que, se o método de inicialização for sobrescrito alterando sua assinatura, não há necessidade de sobrescrever o construtor, porém se o construtor for sobrescrito alterando sua assinatura, é obrigatório que o método de inicialização também seja sobrescrito.<br />
<br />
Detalhes da linguagem…<br />
<tt>[/update]</tt></blockquote>
<br />
A chamada do método de chamada da classe pai da meta classe deve passar os parâmetros esperados pelos argumentos nas assinaturas do construtor e da inicialização da classe. No exemplo acima, esta chamada (precedida por <code>return</code>) é:
</div>
<pre><code class="prettyprint">type.__call__(cls, *args, **kwargs)</code></pre>
<br />
<blockquote>
<tt>[update]</tt><br />
Um detalhe que esqueci de mencionar é que é justamente nessa chamada que o construtor e o método de inicialização são evocados.<br />
<tt>[/update]</tt></blockquote>
<br />
<div style="text-align: justify;">
Os parâmetros passados são os esperados nas assinaturas citadas.
</div>
<br />
[]’s<br />
Cacilhας, La Batalema ℭacilhας, ℒa ℬatalemahttp://www.blogger.com/profile/14265747724618147106noreply@blogger.com0tag:blogger.com,1999:blog-1387996720436450649.post-32654465589867426412014-03-19T18:12:00.001-03:002015-04-18T18:00:43.572-03:00RLock<div style="text-align: justify;">
<img alt="" src="http://photos1.blogger.com/blogger/6505/3295/200/python.png" style="border: none; cursor: crosshair; float: left; margin: 0pt 10px 10px 0pt;" /> Dando continuidade o <a href="http://kodumaro.blogspot.com.br/2014/03/thread-safe.html">artigo sobre <em>thread</em></a>, um recurso muito útil é <a href="http://docs.python.org/2/library/threading.html?highlight=threading.lock#rlock-objects"><em>lock</em> reentrante</a>.<br />
<br />
<em>Lock</em> reentrante é uma variação de <em>lock</em> que pode ser realocado múltiplas vezes pelo mesmo <em>thread</em> e não pode ser liberado por outro <em>thread</em>. É muito útil em funções recursivas, mas funciona também para garantir que o <em>lock</em> seja alocado e liberado pelo mesmo <em>thread</em>.<br />
<br />
A fábrica (<em>factory</em>) para criar <em>locks</em> reentrantes é <code>threading.RLock</code>.<br />
<br />
É preciso tomar cuidado para que todos os <em>threads</em> compartilhem o mesmo <em>lock</em>, senão ele se torna inútil:
</div>
<pre><code class="prettyprint">lock = RLock()
thr1 = Thread(target=func1, args=(lock, ))
thr2 = Thread(target=func2, args=(lock, ))
thr3 = Thread(target=func3, args=(lock, ))</code></pre>
<br />
<div style="text-align: justify;">
Dentro da função, é preciso alocá-lo (<code>acquire</code>) no inicío e liberá-lo (<code>release</code>) ao final. Por exemplo:
</div>
<pre><code class="prettyprint">def func1(lock):
lock.acquire()
try:
# executa o procedimento
...
finally:
lock.release()</code></pre>
<br />
<h3>
Protegendo um objeto mutável</h3>
<div style="text-align: justify;">
Uma utilidade para o <em>lock</em> reentrante é proteger métodos que alterem o conteúdo de um objeto.<br />
<br />
Imagine que temos uma classe <code>Person</code> com dados, como <code>identity_code</code> (CPF) que podem sofrer alterações em <em>threads</em> diferentes (sei que não é uma boa abordagem, mas apenas como exemplo).<br />
<br />
Podemos criar um decorador que torna um método <em>thread-safe</em> usando <em>lock</em> reentrante:
</div>
<pre><code class="prettyprint">def lock(wrapped):
lock_ = RLock()
@wraps(wrapped)
def wrapper(*args, **kwargs):
with lock_:
return wrapped(*args, **kwargs)
return wrapper</code></pre>
<br />
<div style="text-align: justify;">
Esse decorador pode ser usado nos <em>setters</em> de cada propriedade:
</div>
<pre><code class="prettyprint">class Person(object):
...
@property
def identity_code(self):
return self.__identity_code
@identity_code.setter
@lock
def identity_code(self, value):
self.__identity_code = value
...</code></pre>
<br />
<div style="text-align: justify;">
Na verdade essa abordagem não resolve 100% o problema, mas já reduz muito a ocorrência de <em>bugs</em>.
</div>
<h3>
Protegendo qualquer objeto</h3>
<div style="text-align: justify;">
Porém a abordagem acima apenas protege parcialmente o objeto e não funciona para classes de terceiros.<br />
<br />
Outra abordagem é usar um <em>lock</em> para todo o objeto, tanto leitura quanto gravação, agnóstico a qual objeto está sendo protegido. Assim, não há necessidade de usarmos propriedades.<br />
<br />
Vamos criar uma classe para trancar qualquer objeto:
</div>
<pre><code class="prettyprint">class ObjectLocker(object):
def __init__(self, obj):
self.__obj = obj
self.__lock = RLock()
def __enter__(self):
self.__lock.acquire()
return self.__obj
def __exit__(self, etype, exc, traceback):
self.__lock.release()</code></pre>
<br />
<div style="text-align: justify;">
No código a instância dessa classe será passada para os <em>threads</em>, que terá de usar <code>with</code> para acessar o objeto original.<br />
<br />
Ao usar <code>with</code>, o objeto original será trancado para o <em>thread</em> atual e liberado ao final.<br />
<br />
A passagem será:
</div>
<pre><code class="prettyprint">locker = ObjectLocker(Person(...))
thr = Thread(target=func, args=(locker, ))</code></pre>
<br />
<div style="text-align: justify;">
Dentro da(s) função(ões) <code>func</code> a instância de <code>Person</code> deve ser acessa da seguinta forma:
</div>
<pre><code class="prettyprint">with locker as person:
name = person.name
person.identity_code = data['identity_code']</code></pre>
<br />
<div style="text-align: justify;">
Espero que os exemplos tenham sido úteis.<br />
<br /></div>
[]’s<br />
Cacilhας, La Batalemaℭacilhας, ℒa ℬatalemahttp://www.blogger.com/profile/14265747724618147106noreply@blogger.com0tag:blogger.com,1999:blog-1387996720436450649.post-35269322343976115712014-03-15T09:40:00.003-03:002014-03-15T09:45:17.381-03:00Thread-safe<div style="text-align: justify;">
<img alt="" src="http://photos1.blogger.com/blogger/6505/3295/200/python.png" style="border: none; cursor: crosshair; float: left; margin: 0pt 10px 10px 0pt;" /> Tenho tido a necessidade de lidar com muitas bibliotecas de terceiros e teno percebi um erro (ou seria uma <em>abordagem</em>?) comum nas mais novas: quase nenhuma delas é <em>thread-safe</em>.<br />
<br />
Acredito que, com o modismo do uso de <a href="https://pypi.python.org/pypi/greenlet">corrotinas</a> (chamadas <em>lightweight threads</em>), os programadores mais novos passaram a considerar os <em>threads</em> de sistema obsoletos, deixando de tomar cuidados essenciais para boas bibliotecas.<br />
<br />
Bem, tenho uma novidade para vocês: <em>threads</em> não são obsoletos e corrotinas não resolvem todos os problemas do mundo. Há situações em que usar corrotinas pode ser a melhor opção sim, mas em alguns casos os bons e velhos <em>threads</em> ainda são o salva vidas.<br />
<br />
Para que isso seja possível, na criação de bibliotecas é necessário tomar alguns cuidados:<br />
<ul>
<li>Prefira sempre que possível usar objetos imutáveis. Prefira tuplas, <em>strings</em>, tipos numéricos básicos, etc.</li>
<li>Evite permitir que objetos agregados façam alteração em seu objeto contentor sempre que possível.</li>
<li>Em todos métodos e propriedades de um objeto que pode ser compartilhado (como o contentor citado) que alterem o estado do objeto, inicie com um <a href="http://docs.python.org/2/library/threading.html?highlight=threading#rlock-objects"><code>RLock</code></a>, chamando seu método <code>acquire</code>, e encerre chamando seu método <code>release</code>. Tome cuidado para que seja usada a mesma instância de <code>RLock</code>!</li>
<li>Não tenha medo de usar objetos do módulo <code>threading</code>: <a href="http://docs.python.org/2/library/threading.html?highlight=threading#condition-objects"><code>Condition</code></a>, <a href="http://docs.python.org/2/library/threading.html?highlight=threading#event-objects"><code>Event</code></a>, <a href="http://docs.python.org/2/library/threading.html?highlight=threading#lock-objects"><code>Lock</code></a>, <a href="http://docs.python.org/2/library/threading.html?highlight=threading#rlock-objects"><code>RLock</code></a> e <a href="http://docs.python.org/2/library/threading.html?highlight=threading#semaphore-objects"><code>BoundedSemaphore</code></a>. Eles são seus amigos. ;-)</li>
<li>Se estiver difícil escrever testes, substitua <code>threading</code> por <code>dummy_threading</code> para os testes unitários, mas use <code>threading</code> para testes de aceitação.</li>
</ul>
</div>
<br />
[]’s<br />
Cacilhας, La Batalema ℭacilhας, ℒa ℬatalemahttp://www.blogger.com/profile/14265747724618147106noreply@blogger.com0tag:blogger.com,1999:blog-1387996720436450649.post-76732561442531745822014-02-18T13:39:00.001-03:002014-02-18T13:40:36.229-03:00Aspectos – parte II: mixins<div style="text-align: justify;">
<img alt="" src="http://photos1.blogger.com/blogger/6505/3295/200/python.png" style="border: none; cursor: crosshair; float: left; margin: 0pt 10px 10px 0pt;" /> Na <a href="http://kodumaro.blogspot.com.br/2014/02/aspectos-1.html">parte I</a> demos uma passada geral no conceito de aspectos. Aqui veremos os <a href="http://en.wikipedia.org/wiki/Mixin"><em>mixins</em></a>.<br />
<br />
<em>Mixins</em> são classes incompletas que apenas atribuem determinado comportamento às classes herdeiras.<br />
<br />
Vamos a um exemplo bem esdrúxulo, mas suficiente: um objeto que armazena notas de alunos em um arquivo.
</div>
<pre><code class="prettyprint">from cPickle import dumps, loads
import gdbm
__all__ = ['Banco', 'Notas']
class Banco(object):
def __init__(self, file=None):
if file is None:
file = 'notas.db'
if isinstance(file, basestring):
file = gdbm.open(file, 'c')
self.file = file
def close(self):
if self.file:
self.file.close()
self.file = None
class Notas(object):
def __init__(self, matricula, db):
self.matricula = matricula
if not isinstance(db, Banco):
raise TypeError(
'expected Banco instance, got {}'
.format(type(db).__name__)
)
self.db = db
try:
self.notas = loads(db[str(matricula)])
except KeyError:
self.notas = {}
def save(self):
db[str(self.matricula)] = dumps(self.notas)
@property
def primeiro_bimestre(self):
return self.notas.get('1bim')
@primeiro_bimestre.setter
def primeiro_bimestre(self, value):
self.notas['1bim'] = float(value)
@property
def segundo_bimestre(self):
return self.notas.get('2bim')
@segundo_bimestre.setter
def segundo_bimestre(self, value):
self.notas['2bim'] = float(value)
@property
def terceiro_bimestre(self):
return self.notas.get('3bim')
@terceiro_bimestre.setter
def terceiro_bimestre(self, value):
self.notas['3bim'] = float(value)
@property
def quarto_bimestre(self):
return self.notas.get('4bim')
@quarto_bimestre.setter
def quarto_bimestre(self, value):
self.notas['4bim'] = float(value)
@property
def recuperacao(self):
return self.notas.get('rec')
@recuperacao.setter
def recuperacao(self, value):
return self.notas['rec'] = float(value)
@property
def media(self):
soma = sum(
self.primeiro_bimestre or 0,
self.segundo_bimestre or 0,
self.terceiro_bimestre or 0,
self.quarto_bimestre or 0,
)
m = soma / 4.
rec = self.recuperacao
if rec is not None:
m = (m + rec) / 2.
return m</code></pre>
<br />
<div style="text-align: justify;">
Repare que temos o mesmo problema apresentando na parte I: está tudo misturado em uma única classe!<br />
<br />
Podemos separar as partes de gerência de banco e serialização em classes diferentes, dedicadas a seu próprio aspecto, chamadas <em>mixins</em>.<br />
<br />
A classe de faz serialização pode ser apenas isso:
</div>
<pre><code class="prettyprint">class NotaSerializavelMixin(object):
def load(self):
s = self.retrieve()
self.notas = loads(s) if s else {}
def __str__(self):
return dumps(self.notas)</code></pre>
<br />
<div style="text-align: justify;">
A gerência de banco vai para outro <em>mixin</em>:
</div>
<pre><code class="prettyprint">class PersistenciaMixin(object):
def retrieve(self):
try:
return self.db[str(self.matricula)]
except KeyError:
return None
def save(self):
db[str(self.matricula)] = str(self)</code></pre>
<br />
<div style="text-align: justify;">
Preferindo, é possível separar a gerência de notas em um <em>mixin</em> também:
</div>
<pre><code class="prettyprint">class NotasMixin(object):
@property
def primeiro_bimestre(self):
return self.notas.get('1bim')
@primeiro_bimestre.setter
def primeiro_bimestre(self, value):
self.notas['1bim'] = float(value)
...
@property
def media(self):
soma = sum(
self.primeiro_bimestre or 0,
self.segundo_bimestre or 0,
self.terceiro_bimestre or 0,
self.quarto_bimestre or 0,
)
m = soma / 4.
rec = self.recuperacao
if rec is not None:
m = (m + rec) / 2.
return m</code></pre>
<br />
<div style="text-align: justify;">
Ao final, a classe principal será apenas uma cola dos <em>mixins</em>:
</div>
<pre><code class="prettyprint">class Notas(NotaSerializavelMixin, PersistenciaMixin, MotasMixin):
def __init__(self, matricula, db):
self.matricula = matricula
if not isinstance(db, Banco):
raise TypeError(
'expected Banco instance, got {}'
.format(type(db).__name__)
)
self.db = db
self.load()</code></pre>
<br />
<div style="text-align: justify;">
A API da classe continua idêntica: recebe o número da matrícula e o banco na instanciação, propriedades para acessar as notas e método <code>save()</code> para salvá-las em arquivo, porém agora cada aspecto está isolado e encapsulado em seu próprio <em>mixin</em>.
</div>
<br />
[]’s<br />
Cacilhας, La Batalema ℭacilhας, ℒa ℬatalemahttp://www.blogger.com/profile/14265747724618147106noreply@blogger.com0tag:blogger.com,1999:blog-1387996720436450649.post-78471928646718640422014-02-18T12:34:00.001-03:002016-05-21T09:20:50.976-03:00Aspectos – parte I<div style="text-align: justify;">
<blockquote>Atualizado no <a href="http://cacilhas.info/kodumaro/2016/04/aspectos.html"><em>blog</em> novo</a>.</blockquote>
<br />
<img alt="" src="https://photos1.blogger.com/blogger/6505/3295/200/python.png" style="border: none; cursor: crosshair; float: left; margin: 0pt 10px 10px 0pt;"> Um paradigma muito útil é a <a href="http://pt.wikipedia.org/wiki/Programa%C3%A7%C3%A3o_orientada_a_aspecto">Programação orientada a Aspectos</a>.<br />
<br />
Consiste em separar e encapsular as funcionalidades de um código conforme sua importância.<br />
<br />
Nesta primeira parte, abordaremos de forma simples tal separação e deixaremos o conceito de <a href="http://en.wikipedia.org/wiki/Mixin"><em>mixins</em></a> para a <a href="http://kodumaro.blogspot.com.br/2014/02/aspectos-2.html">parte II</a>.<br />
<br />
Vamos começar com um exemplo: imagine uma <em>view</em> que modifica o estado de um objeto, retornando um <em>hash</em> do novo estado:
</div>
<pre><code class="prettyprint">@app.route('/people/<uuid>/', methods=['PATCH'])
def update_person(uuid):
person = db.person.find({ '_id': uuid }).first()
if not person:
raise Http404
try:
data = json.loads(request.data)
except ValueError:
return json.dumps({ 'error': 'invalid request' }), \
400, \
{ 'Content-Type': 'application/json' }
person.update(data)
db.person.save(person)
r = [(str(k), repr(v)) for k, v in person.iteritems()]
r.sort()
s = ';'.join('{}:{}'.format(k, v) for k, v in r)
return json.dumps({ 'etag': md5(s).hexdigest() }), \
200, \
{ 'Content-Type': 'application/json' }</uuid></code></pre>
<br />
<div style="text-align: justify;">
A solução atende, mas é de difícil manutenção. Perceba que a função chamada <code>update_person</code> (atualiza pessoa) faz muito mais do que simplesmente atualizar os dados:
</div>
<ul>
<li>Recupera o documento do banco, retornando 404 se não existir;</li>
<li>Faz os <em>parsing</em> dos dados recebidos, retornando 400 em caso de erro;</li>
<li>Efetivamente atualiza o documento;</li>
<li>Serializa o objeto para a resposta;</li>
<li>Gera um <em>hash</em> da serialização;</li>
<li>Responde a requisição com formato conveniente.</li>
</ul>
<br />
<div style="text-align: justify;">
Cada um desses passos é um <strong>aspecto</strong> do processo e pode ser isolado do restante.<br />
<br />
Vamos então separar o primeiro aspecto: recuperação do documento.
</div>
<pre><code class="prettyprint">def retrieve_person_aspect(view):
@wraps(view)
def wrapper(uuid):
person = db.person.find({ '_id': uuid }).first()
if not person:
raise Http404
return view(person)
return wrapper
@app.route('/people/<uuid>/', methods=['PATCH'])
@retrieve_person_aspect
def update_person(person):
try:
data = json.loads(request.data)
except ValueError:
return json.dumps({ 'error': 'invalid request' }), \
400, \
{ 'Content-Type': 'application/json' }
person.update(data)
db.person.save(person)
r = [(str(k), repr(v)) for k, v in person.iteritems()]
r.sort()
s = ';'.join('{}:{}'.format(k, v) for k, v in r)
return json.dumps({ 'etag': md5(s).hexdigest() }), \
200, \
{ 'Content-Type': 'application/json' }</uuid></code></pre>
<br />
<div style="text-align: justify;">
Agora a recuperação do documento está isolada, podendo inclusive ser usada em outras <em>views</em>. Nossa <em>view</em> já recebe o documento recuperado e não precisa lidar com o fato dele existir ou não.<br />
<br />
Porém ainda temos muita coisa misturada. Por exemplo, a obtenção e <em>parsing</em> dos dados recebidos: isso caracteriza outro aspecto do código, que não a atualização do documento.<br />
<br />
Podemos portanto, separá-los:
</div>
<pre><code class="prettyprint">def parse_data_aspect(view):
@wraps(view)
def wrapper(person):
try:
data = json.loads(request.data)
except ValueError:
return json.dumps({ 'error': 'invalid request' }), \
400, \
{ 'Content-Type': 'application/json' }
return view(person, data)
return wrapper
def retrieve_person_aspect(view):
...
@app.route('/people/<uuid>/', methods=['PATCH'])
@retrieve_person_aspect
@parse_data_aspect
def update_person(person, data):
person.update(data)
db.person.save(person)
r = [(str(k), repr(v)) for k, v in person.iteritems()]
r.sort()
s = ';'.join('{}:{}'.format(k, v) for k, v in r)
return json.dumps({ 'etag': md5(s).hexdigest() }), \
200, \
{ 'Content-Type': 'application/json' }</uuid></code></pre>
<br />
<div style="text-align: justify;">
A função <code>update_person</code> já está muito mais limpa: atualiza o documento, serializa e retorna o <em>hash</em>, mas ainda faz coisas demais. Vamos separar o tratamento do retorno:
</div>
<pre><code class="prettyprint">def respond_etag_aspect(view):
@wraps(view)
def wrapper(person, data):
response = view(person, data)
return json.dumps({ 'etag': md5(response).hexdigest() }), \
200, \
{ 'Content-Type': 'application/json' }
return wrapper
def parse_data_aspect(view):
...
def retrieve_person_aspect(view):
...
@app.route('/people/<uuid>/', methods=['PATCH'])
@retrieve_person_aspect
@parse_data_aspect
@respond_etag_aspect
def update_person(person, data):
person.update(data)
db.person.save(person)
r = [(str(k), repr(v)) for k, v in person.iteritems()]
r.sort()
return ';'.join('{}:{}'.format(k, v) for k, v in r)</uuid></code></pre>
<br />
<div style="text-align: justify;">
As coisas estão ficando cada vez mais separadas. A única coisa que a função <code>update_person</code> faz agora além de atualizar o documento é serializá-lo. Isso também pode ser isolado:
</div>
<pre><code class="prettyprint">def serialize_person_aspect(view):
@wraps(view)
def wrapper(person, data):
response = view(person, data)
r = [(str(k), repr(v)) for k, v in response.iteritems()]
r.sort()
return ';'.join('{}:{}'.format(k,v) for k, v in r)
def respond_etag_aspect(view):
...
def parse_data_aspect(view):
...
def retrieve_person_aspect(view):
...
@app.route('/people/<uuid>/', methods=['PATCH'])
@retrieve_person_aspect
@parse_data_aspect
@respond_etag_aspect
@serialize_person_aspect
def update_person(person, data):
person.update(data)
db.person.save(person)
return person</uuid></code></pre>
<br />
<div style="text-align: justify;">
Perceba que, com a separação dos aspectos em funções distintas, o código ficou muito mais semântico:
</div>
<ul>
<li><code>retrive_person_aspect</code> apenas recupera o documento do banco;</li>
<li><code>parse_data_aspect</code> apenas faz o <em>parsing</em> dos dados recebidos;</li>
<li><code>respond_etag_aspect</code> apenas gera o formato correto da resposta;</li>
<li><code>serialize_person_aspect</code> apenas serializa o documento;</li>
<li>finalmente, <code>update_person</code> apenas atualiza o documento.</li>
</ul>
<br />
<h3>
Observações</h3>
<ul>
<li><code>db</code> é um objeto de banco de dados MongoDB, apenas para fim de exemplo.</li>
<li><code>app</code> é uma aplicação <a href="http://flask.pocoo.org/">Flask</a>, apenas para fim de exemplo.</li>
<li>A ordem dos decoradores <strong>é importante</strong>.</li>
<li>Os <code>import</code>s foram omitidos:
</li>
</ul>
<pre><code class="prettyprint">import json
from functools import wraps
from hashlib import md5</code></pre>
<br />
<div style="text-align: justify;">
Na <a href="http://kodumaro.blogspot.com.br/2014/02/aspectos-2.html">parte II</a> abordaremos <em>mixins</em>.
</div>
<br />
[]’s<br />
Cacilhας, La Batalema ℭacilhας, ℒa ℬatalemahttp://www.blogger.com/profile/14265747724618147106noreply@blogger.com0tag:blogger.com,1999:blog-1387996720436450649.post-25780010911835185512013-10-12T15:17:00.000-03:002013-10-16T12:27:35.241-03:00Encadeamento de funções<div style="text-align: justify;">
<img alt="Poliedro" src="http://photos1.blogger.com/blogger/6505/3295/200/prog.png" style="border: medium none; cursor: crosshair; float: left; margin: 0pt 10px 10px 0pt;" /> Encadeamento de função é o <em>pattern</em> onde um grupo de funções é encadeado.<br />
<br />
Em uma cadeia, sempre a saída de uma função é a entrada da seguinte, o parâmetro inicial é fornecido à primeira função da cadeia, que segue executando as funções, e o resultado da última função é retornado como resultado da cadeia.<br />
<br />
Vejamos como criar cadeia.</div>
<br />
<h3>
Python</h3>
<div style="text-align: justify;">
A forma mais simples simples de encadear funções é simplesmente efetuar a chamada, como o código <a href="http://python.org/">Python</a> a seguir:</div>
<pre><code class="prettyprint">f1 = lambda x: x * 2
f2 = lambda x: x - 1
f3 = lambda x: x // 3
print(f3(f2(f1(8))))</code></pre>
<br />
<div style="text-align: justify;">
Porém esse código é visualmente confuso e difícil de ser depurado. É conveniente criar uma fábrica (<em>factory</em>) de cadeias:</div>
<pre><code class="prettyprint">chain = lambda *funcs: \
reduce(lambda acc, func: (lambda x: func(acc(x))),
funcs or [lambda x: x])
the_chain = chain(
lambda x: x * 2,
lambda x: x - 1,
lambda x: x // 3,
)
print(the_chain(8))</code></pre>
<br />
<div style="text-align: justify;">
Repare que as funções agora estão na ordem em que são executadas:
</div>
<ol>
<li>O número é dobrado;</li>
<li>O resultado da primeira função é decrementado;</li>
<li>O resultado da terceira função é triplicado e retornado.</li>
</ol>
<br />
<div style="text-align: justify;">
A função <code>reduce()</code> de Python executa a redução de um <a href="http://pt.wikipedia.org/wiki/MapReduce"><em>map/reduce</em></a>: o primeiro parâmetro é uma função que recebe o acumulador e o próximo valor, retornando o resultado parcial.<br />
<br />
O segundo parâmetro de <code>reduce()</code> é a lista a ser reduzida, no caso, a lista de funções ou, caso nenhuma função tenha sido informada, um função vazia que retorna o próprio parâmetro fornecido.<br />
<br />
Com este procedimento, é possível reduzir a lista de funções a uma função representando o encadeamento das funções fornecidas.</div>
<br />
<h3>
Erlang</h3>
<div style="text-align: justify;">
Em <a href="http://www.erlang.org/">Erlang</a> as coisas também podem ser interessantes.<br />
<br />
Criaremos duas funções, uma fábrica a ser exportado (<code>chain/1</code>) e uma função de redução (<code>chain/2</code>) que <strong>não</strong> deve ser exportada:
</div>
<pre><code class="prettyprint">-module(chain).
-export([chain/1]).
chain(Funs) when is_list(Funs) ->
chain(Funs, fun(X) -> X).
chain([], Acc) -> Acc;
chain([Fun|Rest], Acc) when is_function(Fun) ->
chain(Rest, fun(X) -> Fun(Acc(X)) end).</code></pre>
<br />
<div style="text-align: justify;">
Você pode então executar no <em>shell</em>:</div>
<pre><code>1> <strong>c(chain).</strong>
{ok,chain}
2> <strong>Fun = chain:chain([</strong>
2> <strong>fun(X) -> X * 2 end,</strong>
2> <strong>fun(X) -> X - 1 end,</strong>
2> <strong>fun(X) -> X div 3 end</strong>
2> <strong>]).</strong>
#Fun<chain.1.134034448>
3> <strong>Fun(8).</strong>
5
4> </code></pre>
<br />
<h3>
Haskell</h3>
<div style="text-align: justify;">
<a href="http://haskell.org/">Haskell</a> por outro lado já possui uma fábrica de cadeias, usando o carácter <code>$</code>, infelizmente na ordem inversa: primeiro as últimas funções a serem executadas, e por último as primeiras.<br />
<br />
Então, por exemplo: <code>f1 $ f2 $ f3 x</code> é executado como <code>f1 (f2 (f3 x))</code>.<br />
<br />
Crie um módulo:
</div>
<pre><code class="prettyprint">module Chain where
the_chain :: Int -> Int
the_chain n = (`div` 3) $ (\x -> x - 1) $ (* 2) n</code></pre>
<br />
<div style="text-align: justify;">
No <em>prompt</em> do <code>ghci</code> execute:
</div>
<pre><code>Prelude> <strong>:load chain.hs</strong>
[1 of 1] Compiling Chain ( chain.hs, interpreted )
Ok, modules loaded: Chain.
*Chain> <strong>the_chain 8</strong>
5
*Chain> </code></pre>
<br />
[]’s<br />
Cacilhας, La Batalemaℭacilhας, ℒa ℬatalemahttp://www.blogger.com/profile/14265747724618147106noreply@blogger.com0tag:blogger.com,1999:blog-1387996720436450649.post-51560008472747267522013-09-27T12:45:00.003-03:002016-05-21T09:18:50.232-03:00Introdução ao código ASCII (para iniciantes)<div style="text-align: justify;">
<blockquote>Atualizado no <a href="http://cacilhas.info/kodumaro/2016/05/ascii.html"><em>blog</em> novo</a>.</blockquote>
<br />
<img alt="Glider" src="https://2.bp.blogspot.com/_rGfO7DAuOSE/SwSZGIY_eXI/AAAAAAAAATA/Gh-qDqdTMX0/s200/glider.png" style="border: none; cursor: crosshair; float: left; height: 55px; margin: 0 10px 10px 0; width: 55px;">
Código <a href="http://www.wps.com/projects/codes/X3.4-1963/">ASCII</a> é a codificação de caracteres para valores numéricos de 7 bits mais aceita mundialmente e significa <em>American Standard Code for Information Interchange</em> – portanto, nada de ASC-2, por favor.<br />
<br />
O ASCII não permite acentos ou diacríticos, apenas os caracteres mais comuns e uma série de 33 caracteres de controle. Porém, como a menor palavra binária (sequência de <a href="http://pt.wikipedia.org/wiki/Bit">bits</a>) usada é o <a href="http://pt.wikipedia.org/wiki/Byte">byte</a>, que usa 8 bits, um a mais que o ASCII, é possível criar <em>supersets</em> com o dobro<a href="#footnote-1"><sup>1</sup></a> da capacidade como, por exemplo, o <a href="http://pt.wikipedia.org/wiki/ISO_8859-1">Latin-1</a> e o <a href="http://en.wikipedia.org/wiki/Windows-1252">CP-1252</a>.<br />
<br />
Para quem está começando a tentar entender o código ASCII, é preciso saber que ele é composto de grupos. O primeiro grupo é o que possui sequência binária <code>00xxxxx</code>, ou seja, dois zeros nas primeiras casas e qualquer combinação nas 5 seguintes. Isso dá uma combinação de 32 caracteres, com código de 0 (<code>0000000</code>) a 31 (<code>0011111</code>), e consiste nos caracteres de controle, como nulo (0), os caracteres de mudança de linha (10 e 13), o <em>backspace</em> (8), o <em>escape</em> (27) e o <em>tab</em> (9).<br />
<br />
Há uma exceção, um carácter de controle perdido fora dessa sequência: o <em>delete</em> (127 – <code>1111111</code>).<br />
<br />
O grupo seguinte, <code>010xxxx</code> (32 a 47) é uma sequência de caracteres de pontuação e símbolos matemáticos, a começar pelo espaço (32).<br />
<br />
Então começam os números, dentro do grupo <code>011xxxx</code>. Os números começam em <code>0110000</code> (48) e seguem até <code>0111001</code> (57). Uma forma fácil de pensar qual o código de um dígito numérico é somar 48 ao valor do número. Por exemplo, o código de <code>7</code> é (48+7=) 55.<br />
<br />
O grupo <code>011xxxx</code> segue com mais pontuações e símbolos matemáticos.<br />
<br />
O o grupo seguinte é o das letras maiúsculas: <code>10xxxxx</code>. O primeiro elemento, 64 (<code>1000000</code>), é o arroba (<code>@</code>), seguido das letras. Para saber o código de uma letra é só somar 64 ao índice da letra no alfabeto. Por exemplo, a letra <code>F</code> é 6ª letra do alfabeto, portanto seu código é (64+6=) 70.<br />
<br />
Depois do <code>Z</code> (90), continuam mais pontuações e símbolos matemáticos, terminando com <em>underscore</em> (<code>–</code>, 95 – <code>1011111</code>).<br />
<br />
A próxima sequência, começando pela crase, são as letras minúsculas. A sequência é idêntica à anterior, apenas trocando o 6º bit (da direita pra esquerda) por 1: <code>11xxxxx</code>, o que soma 32 ao número, e as letras coincidem o mesmo código.<br />
<br />
Ou seja, se o código de <code>F</code> é 70, o código de <code>f</code> é (70+32=) 102.<br />
<br />
Como esperado, a sequência após o <code>z</code> (122) continua com pontuações e símbolos matemáticos.
<br />
<h3>
Exemplo</h3>
Como exemplo, vamos codificar a palavra <code>Kodumaro</code>:<br/>
</div>
<pre><code>K = 64 + 11 = 75
o = 64 + 15 + 32 = 111
d = 64 + 4 + 32 = 100
u = 64 + 21 + 32 = 117
m = 64 + 13 + 32 = 109
a = 64 + 1 + 32 = 97
r = 64 + 18 + 32 = 114
o = 64 + 15 + 32 = 111
Kodumaro ≡ 75, 111, 100, 117, 109, 97, 114, 111</code></pre>
<br />
<div style="text-align: justify;">
Se você preferir, pode pensar em bits (é incrível, mas é mais simples): o 7º bit (1º da esquerda) é sempre <code>1</code> (letra), o 6º (2º da esquerda) é <code>0</code> para maiúsculas e <code>1</code> para minúsculas, os 5 seguintes são a ordem da letra no alfabeto:<br/>
</div>
<pre><code>A = 1 = 00001
B = 2 = 00010
C = 3 = 00011
D = 4 = 00100
E = 5 = 00101
F = 6 = 00110
G = 7 = 00111
H = 8 = 01000
I = 9 = 01001
J = 10 = 01010
K = 11 = 01011
L = 12 = 01100
M = 13 = 01101
N = 14 = 01110
O = 15 = 01111
P = 16 = 10000
Q = 17 = 10001
R = 18 = 10010
S = 19 = 10011
T = 20 = 10100
U = 21 = 10101
V = 22 = 10110
W = 23 = 10111
X = 24 = 11000
Y = 25 = 11001
Z = 26 = 11010
</code></pre>
<br />
<div style="text-align: justify;">
Voltando ao <code>Kodumaro</code>:<br/>
</div>
<pre><code>K = (letra)(maiúscula)11ª – 1.0.01011 – 1001011
o = (letra)(minúscula)15ª – 1.1.01111 – 1101111
d = (letra)(minúscula) 4ª – 1.1.00100 – 1100100
u = (letra)(minúscula)21ª – 1.1.10101 – 1110101
m = (letra)(minúscula)13ª – 1.1.01101 – 1101101
a = (letra)(minúscula) 1ª – 1.1.00001 – 1100001
r = (letra)(minúscula)18ª – 1.1.10010 – 1110010
o = (letra)(minúscula)15ª – 1.1.01111 – 1101111</code></pre>
<br />
<div style="text-align: justify;">
E de fato é assim que é codificado e armazenado:<br/>
</div>
<pre><code>1001011.1101111.1100100.1110101.1101101.1100001.1110010.1101111</code></pre>
<br />
<div style="text-align: justify;">
Ou melhor, em bytes:<br/>
</div>
<pre><code>0100101101101111011001000111010101101101011000010111001001101111</code></pre>
<br />
<br />
[]’s<br />
Cacilhας, La Batalema<br/>
<br />
<br />
<div style="font-size: x-small; text-align: justify;">
<sup id="footnote-1">1</sup>A cada bit que se acrescenta a uma palavra binária, sua quantidade de combinações dobra.
</div>ℭacilhας, ℒa ℬatalemahttp://www.blogger.com/profile/14265747724618147106noreply@blogger.com0tag:blogger.com,1999:blog-1387996720436450649.post-37729633979197523242013-09-18T19:52:00.000-03:002014-04-12T13:19:44.487-03:00Um editor de textos rapidinho<div style="text-align: justify;">
<img alt="" src="http://photos1.blogger.com/blogger/6505/3295/200/python.png" style="border: none; cursor: crosshair; float: left; margin: 0pt 10px 10px 0pt;" /> Veremos como é simples criar uma aplicação gráfica rapidamente usando <a href="https://wiki.python.org/moin/TkInter">Tkinter</a>.<br />
<br />
Vamos começar a a partir de um <i>boilerplate</i>:
</div>
<br />
<pre><code class="prettyprint">#!/usr/bin/env python
# coding: UTF-8
from __future__ import absolute_import, division, print_function, unicode_literals
#-------------------------------------------------------------
# Cabeçalhos
#
# Aqui vão entrar os imports
__all__ = ['Editor']
#-------------------------------------------------------------
class Editor(object):
def mainloop(self):
pass
#-------------------------------------------------------------
# Rodapé
if __name__ == '__main__':
app = Editor()
app.mainloop()
</code></pre>
<br />
<div style="text-align: justify;">
A primeira coisa que precisamos fazer é criar nossa janela raiz. Para tanto, adicione aos cabeçalhos o <code>import</code>:
</div>
<br />
<pre><code class="prettyprint">from Tkinter import *
</code></pre>
<br />
<h3>
Método construtor</h3>
<div style="text-align: justify;">
Em seguida, no começo da classe <code>Editor</code>, vamos começar a escrever nosso construtor:
</div>
<br />
<pre><code class="prettyprint">class Editor(object):
def __init__(self):
root = self.root = Tk()
root.title('EditPy')
</code></pre>
<br />
<div style="text-align: justify;">
Precisamos então de um <i>frame</i> para colocar os botões de abrir, salvar e salvar-como:
</div>
<br />
<pre><code class="prettyprint"> fbuttons = Frame(root)
Button(fbuttons, text='Open', command=self.open) \
.pack(side=LEFT)
Button(fbuttons, text='Save', command=self.save) \
.pack(side=LEFT)
Button(fbuttons, text='Save As', command=self.save_as) \
.pack(side=LEFT)
</code></pre>
<br />
<div style="text-align: justify;">
O pai (<i>master</i>) do <i>frame</i> <code>fbuttons</code> é nossa janela raiz e o pai dos botões é o <i>frame</i>.<br />
<br />
Agora precisamos de uma caixa de texto para editar e exibir o conteúdo dos arquivos. Primeiro vá aos cabeçalhos novamente e acrescente o <code>import</code>:
</div>
<br />
<pre><code class="prettyprint">from ScrolledText import ScrolledText
</code></pre>
<br />
<div style="text-align: justify;">
Então, continuando o construtor, crie a caixa de texto com rolagem:
</div>
<br />
<pre><code class="prettyprint"> steditor = self.steditor = ScrolledText(root)
</code></pre>
<br />
<div style="text-align: justify;">
Para fechar o construtor só falta exibir o <i>frame</i> e a caixa de texto, e colocar o foco na caixa:
</div>
<br />
<pre><code class="prettyprint"> fbuttons.pack(expand=True, fill=X)
steditor.pack(expand=True, fill=BOTH)
steditor.focus()
</code></pre>
<br />
<h3>
<i>Loop</i> principal</h3>
<div style="text-align: justify;">
Se você tentar rodar o código agora, <b>nada</b> acontece. Isso porque o método <code>mainloop()</code> faz isso: absolutamente nada.<br />
<br />
Precisamos então, neste método, chamar o <i>loop</i> principal do Tkinter. Para isso, altere o método:
</div>
<br />
<pre><code class="prettyprint"> def mainloop(self):
self.root.mainloop()
</code></pre>
<br />
<div style="text-align: justify;">
Chamamos então o <i>loop</i> principal através da janela raiz (<code>root</code>).
</div>
<br />
<h3>
Abrir um arquivo</h3>
<div style="text-align: justify;">
Porém coisas estranhas e erros esdrúxulos podem acontecer, pois ainda não implementamos nenhum dos métodos chamados pelos botões – <code>self.open</code>, <code>self.save</code> e <code>self.save_as</code>.<br />
<br />
Parece-me justo que comecemos pelo método de abertura de arquivo. Criemos a assinatura do método:
</div>
<br />
<pre><code class="prettyprint"> def open(self):
</code></pre>
<br />
<div style="text-align: justify;">
Para abrir um arquivo, precisamos de uma ferramenta chamada <code>askopenfilename</code> que precisamos importar, então nos cabeçalhos acrescente:
</div>
<br />
<pre><code class="prettyprint">from tkFileDialog import askopenfilename
</code></pre>
<br />
<div style="text-align: justify;">
Então, de volta ao método <code>open()</code>, podemos pegar o nome do arquivo e carregá-lo:
</div>
<br />
<pre><code class="prettyprint"> filename = askopenfilename(title='EditPy | Open')
if filename:
self.filename = filename
self.load_file()
</code></pre>
<br />
<div style="text-align: justify;">
O método <code>load_file()</code> é quem vai de fato carregar o arquivo, mas precisamos antes apagar o conteúdo da caixa de texto:
</div>
<br />
<pre><code class="prettyprint"> def load_file(self):
filename = self.filename
steditor = self.steditor
steditor.delete('@0,0', 'end')
with open(filename) as fd:
steditor.insert('@0,0', fd.read())
</code></pre>
<br />
<div style="text-align: justify;">
O método <code>delete()</code> da caixa de texto apaga parte do conteúdo da caixa e os parâmetros são os índices de começo e fim:
</div>
<ul>
<li><code>@0,0</code> significa linha 0, coluna 0 (começo do texto);</li>
<li><code>end</code> significa o final do texto.</li>
</ul>
<br />
<div style="text-align: justify;">
O método <code>insert()</code> inserte a <i>string</i> (lida do descritor de arquivo) na posição indicada (<code>@0,0</code>).
</div>
<br />
<h3>
Salvando o texto</h3>
<div style="text-align: justify;">
Para salvar o texto, precisamos implementar o método <code>save()</code>. Ele precisa:
</div>
<ol>
<li>Verificar se temos um nome de arquivo – se não tivermos, é um <code>save_as</code>.</li>
<li>Abrir o arquivo para escrita.</li>
<li>Obter o texto da caixa de texto.</li>
<li>Gravar o texto no arquivo.</li>
</ol>
<br />
<div style="text-align: justify;">
Simples, indolor e o código é intuitivo:
</div>
<br />
<pre><code class="prettyprint"> def save(self):
filename = self.filename
if not filename:
return self.save_as()
with open(filename, 'w') as fd:
fd.write(
self.steditor.get('@0,0', 'end')
)
</code></pre>
<br />
<div style="text-align: justify;">
Repare nos índices usados no método <code>get()</code>.<br />
<br />
Em seguida é preciso saber o que fazer quando não temos o nome do arquivo ou quando escolhemos <i>Save As</i>.<br />
<br />
Primeiro a assinatura do método:
</div>
<br />
<pre><code class="prettyprint"> def save_as(self):
</code></pre>
<br />
<div style="text-align: justify;">
Caso haja um nome de arquivo, é honesto usá-lo como ponto de partida para caixa de diálogo de salvamento. Para isso precisamos separar o nome de diretório do nome base do arquivo e uma forma de fazer isso é com o método de <i>string</i> <code>rfind</code>.<br />
<br />
Para sabermos qual o separador de diretórios usado, adicione aos <code>import</code>s:
</div>
<br />
<pre><code class="prettyprint">from os import path
</code></pre>
<br />
<div style="text-align: justify;">
Então continue no método:
</div>
<br />
<pre><code class="prettyprint"> filename, directory = self.filename, None
if filename and path.sep in filename:
index = filename.rfind(path.sep) + 1
directory = filename[:index]
filename = filename[index:]
</code></pre>
<br />
<blockquote style="text-align: justify;"><tt>[update 2014-04-12]</tt><br/>
Optei por usar <code>rfind</code>, mas poderia ter usado <code>path.basename</code> e <code>path.dirname</code>. É uma questão de escolha e estilo.<br/>
<tt>[/update]</tt></blockquote>
<div style="text-align: justify;">
Feito o <em>slice</em>, já podemos exibir a caixa de diálogo de salvamento. Para isso precisamos da ferramenta <code>asksaveasfilename</code>.<br />
<br />
Modifique o <code>import</code> do <code>askopenfilename</code> para:
</div>
<br />
<pre><code class="prettyprint">from tkFileDialog import askopenfilename, asksaveasfilename
</code></pre>
<br />
<div style="text-align: justify;">
Continuando agora no método <code>save_as()</code>, podemos exibir a caixa de diálogo e, se algum arquivo for informado, chamar o método <code>save()</code>:
</div>
<br />
<pre><code class="prettyprint"> filename = asksaveasfilename(
title = 'EditPy | Save As',
initialfile = filename,
initialdir = directory,
)
if filename:
self.filename = filename
self.save()
</code></pre>
<br />
<div style="text-align: justify;">
E pronto! Já pode testar seu editor de texto!
</div>
<br />
<h3>
Lapidando</h3>
<div style="text-align: justify;">
Uma forma de melhorar um pouco o visual da aplicação é usando a extensão <i>ajulejada</i> do <code>tk</code>, chamada <a href="http://wiki.tcl.tk/14796"><code>ttk</code></a>.<br />
<br />
Para tanto, basta adicionar ao cabeçalho, no <b>final</b> dos <code>import</code>s:
</div>
<br />
<pre><code class="prettyprint">from ttk import *
</code></pre>
<br />
<div style="text-align: justify;">
Você também pode usar os métodos <code>wm_protocol()</code> e <code>bind_all()</code> da janela raiz para adicionar funcionalidades interessantes, mas isso é história pra outro dia. ;-)
</div>
<br />
[]’s<br />
Cacilhας, La Batalemaℭacilhας, ℒa ℬatalemahttp://www.blogger.com/profile/14265747724618147106noreply@blogger.com0tag:blogger.com,1999:blog-1387996720436450649.post-20270987619760103052013-07-29T12:35:00.000-03:002013-07-30T17:59:51.921-03:00Tail call optimization<img style="float: left; margin: 0 10px 10px 0; cursor: crosshair; width: 55px; height: 55px; border: none;" src="http://2.bp.blogspot.com/_rGfO7DAuOSE/SwSZGIY_eXI/AAAAAAAAATA/Gh-qDqdTMX0/s200/glider.png" alt="Glider" /> <a href="http://www.erlang.org/">Erlang</a>, enquanto derivação funcional de <a href="https://pt.wikipedia.org/wiki/Prolog">Prolog</a>, não possui <em>loop</em> reiterativo e resolve suas reiterações com recursão.<br/><br/>
Porém as aplicações em Erlang são feitas para funcionar ininterruptamente por semanas ou anos, imagine então como ficaria a memória com o empilhamento de chamadas de função!<br/><br/>
Para resolver isso, Erlang usa um recurso chamado <em>tail call optimization</em>.<br/><br/>
Sempre que o fluxo de execução chega à última chamada da função (chamada <em>last call</em> ou <em>tail call</em>), antes da execução desta chamada, a função é removida da pilha de memória e a memória usada por ela já se torna candidata à coleta de lixo (<em>garbage collection</em>).<br/><br/>
Vamos a um exemplo. Tomemos a implementação <em>body recursive</em> de fatorial:<br/>
<pre><code class="prettyprint">fact(0) -> 1;
fact(N) when N > 0 -> N * fact(N-1).</code></pre><br/>
Agora vamos executar: <code>fact(5).</code> – O que acontece?<br/></br>
<ul>
<li>5 casa com o guarda <code>N > 0</code>, então entramos na segunda assinatura da função <code>fact/1</code>.</li>
<li>5 é vinculado a <code>N</code>. A pilha contém <code>fact(5)</code> e <code>N = 5</code>.</li>
<li>É identificada a chamada a <code>erlang:'-'/2</code> passando os parâmetros 5 e 1.</li>
<li>A chamada retorna 4, então é identificada a chamada a <code>fact(4)</code>.</li>
<li>4 casa com o guarda <code>N > 0</code>, então entramos na segunda assinatura da função <code>fact/1</code>.</li>
<li>4 é vinculado a <code>N</code>. A pilha contém <code>fact(5)</code>, <code>N = 5</code>, <code>fact(4)</code> e <code>N = 4</code>.</li>
<li>É identificada a chamada a <code>erlang:'-'/2</code> passando os parâmetros 4 e 1.</li>
<li>A chamada retorna 3, então é identificada a chamada a <code>fact(3)</code>.</li>
<li>3 casa com o guarda <code>N > 0</code>, então entramos na segunda assinatura da função <code>fact/1</code>.</li>
<li>3 é vinculado a <code>N</code>. A pilha contém <code>fact(5)</code>, <code>N = 5</code>, <code>fact(4)</code>, <code>N = 4</code>, <code>fact(3)</code> e <code>N = 3</code>.</li>
<li>É identificada a chamada a <code>erlang:'-'/2</code> passando os parâmetros 3 e 1.</li>
<li>A chamada retorna 2, então é identificada a chamada a <code>fact(2)</code>.</li>
<li>2 casa com o guarda <code>N > 0</code>, então entramos na segunda assinatura da função <code>fact/1</code>.</li>
<li>2 é vinculado a <code>N</code>. A pilha contém <code>fact(5)</code>, <code>N = 5</code>, <code>fact(4)</code>, <code>N = 4</code>, <code>fact(3)</code>, <code>N = 3</code>, <code>fact(2)</code> e <code>N = 2</code>.</li>
<li>É identificada a chamada a <code>erlang:'-'/2</code> passando os parâmetros 2 e 1.</li>
<li>A chamada retorna 1, então é identificada a chamada a <code>fact(1)</code>.</li>
<li>1 casa com o guarda <code>N > 0</code>, então entramos na segunda assinatura da função <code>fact/1</code>.</li>
<li>1 é vinculado a <code>N</code>. A pilha contém <code>fact(5)</code>, <code>N = 5</code>, <code>fact(4)</code>, <code>N = 4</code>, <code>fact(3)</code>, <code>N = 3</code>, <code>fact(2)</code>, <code>N = 2</code>, <code>fact(1)</code> e <code>N = 1</code>.</li>
<li>É identificada a chamada a <code>erlang:'-'/2</code> passando os parâmetros 1 e 1.</li>
<li>A chamada retorna 0, então é identificada a chamada a <code>fact(0)</code>.</li>
<li>0 (zero) casa com a primeira assinatura da função, <code>fact(0)</code>.</li>
<li>A pilha contém <code>fact(5)</code>, <code>N = 5</code>, <code>fact(4)</code>, <code>N = 4</code>, <code>fact(3)</code>, <code>N = 3</code>, <code>fact(2)</code>, <code>N = 2</code>, <code>fact(1)</code>, <code>N = 1</code> e <code>fact(0)</code>.<a href="#memory-heap-footnote" id="memory-heap-anchor" name="memory-heap-anchor"><sup>†</sup></a></li>
<li><code>fact(0)</code> retorna 1 e é desempilhado.</li>
<li>Na pilha de <code>fact(1)</code> é reconhecida a <em>last call</em> <code>erlang:'*'/2</code> com os parâmetros 1 e 1, então <code>fact(1)</code> é desempilhado, assim como suas variáveis.</li>
<li>Neste ponto tempos na pilhas: <code>fact(5)</code>, <code>N = 5</code>, <code>fact(4)</code>, <code>N = 4</code>, <code>fact(3)</code>, <code>N = 3</code>, <code>fact(2)</code>, <code>N = 2</code> e <code>1*1</code>.</li>
<li><code>1*1</code> retorna 1 e é desempilhado.</li>
<li>Na pilha de <code>fact(2)</code> é reconhecida a <em>last call</em> <code>erlang:'*'/2</code> com os parâmetros 2 e 1, então <code>fact(2)</code> é desempilhado, assim como suas variáveis.</li>
<li><code>2*1</code> retorna 2 e é desempilhado.</li>
<li>Na pilha de <code>fact(3)</code> é reconhecida a <em>last call</em> <code>erlang:'*'/2</code> com os parâmetros 3 e 2, então <code>fact(3)</code> é desempilhado, assim como suas variáveis.</li>
<li><code>3*2</code> retorna 6 e é desempilhado.</li>
<li>Na pilha de <code>fact(4)</code> é reconhecida a <em>last call</em> <code>erlang:'*'/2</code> com os parâmetros 4 e 6, então <code>fact(4)</code> é desempilhado, assim como suas variáveis.</li>
<li><code>4*6</code> retorna 24 e é desempilhado.</li>
<li>Na pilha de <code>fact(5)</code> é reconhecida a <em>last call</em> <code>erlang:'*'/2</code> com os parâmetros 5 e 24, então <code>fact(4)</code> é desempilhado, assim como suas variáveis.</li>
<li><code>5*24</code> retorna 120 e é desempilhado.</li>
</ul><br/>
<a href="#memory-heap-anchor" id="memory-heap-footnote" name="memory-heap-footnote"><sup>†</sup></a>Agora repare como a pilha ficou sobrecarregada com poucas chamadas… imagine com <code>fact(200)</code>!<br/><br/>
Essa foi uma implementação <em>body recursive</em>, que não aproveita as vantagens da <em>tail call optimization</em>.
Vamos então a uma implementação <em>tail recursive</em>:<br/>
<pre><code class="prettyprint">fact(N) when is_integer(N), N >= 0 -> fact(N, 1).
fact(0, Acc) -> Acc;
fact(N, Acc) -> fact(N-1, N*Acc).</code></pre>
<blockquote><tt>[update 2013-07-30]</tt><br/>
Acho de difícil leitura o uso da vírgula como operador de conjunção em guardas (coloquei no código apenas porque é o mais usado), então você também pode escrever a função <code>fact/1</code> assim:<br/>
<pre><code class="prettyprint">fact(N) when is_integer(N) andalso N >= 0 -> fact(N, 1).</code></pre><br/>
É mais verborrágico, porém mais claro.<br/>
<tt>[/update]</tt></blockquote>
A função <code>fact/2</code> não possui guarda pois não será exportada, apenas é consumida por <code>fact/1</code>.<br/><br/>
Chamando <code>fact(5)</code>:<br/>
<ul>
<li>5 é inteiro e maior ou igual a 0, então pode ser tratado pela função <code>fact/1</code>.</li>
<li>5 é vinculado a <code>N</code>. Neste ponto temos na filha <code>fact(5)</code> e <code>N = 5</code>.</li>
<li>É identificada a <em>last call</em> <code>fact/2</code> com os parâmetros 5 e 1, então <code>fact(5)</code> é desempilhada, assim como suas variáveis.</li>
<li>5 é diferente de 0, então caímos na segunda assinatura de <code>fact/2</code>, onde 5 é vinculado a <code>N</code> e 1 é vinculado a <code>Acc</code>.</li>
<li>Neste ponto temos na pilha: <code>fact(5, 1)</code>, <code>N = 5</code> e <code>Acc = 1</code>.</li>
<li>É executada a função <code>erlang:'-'/2</code> com os parâmetros 5 e 1, retornando 4.</li>
<li>É executada a função <code>erlang:'*'/2</code> com os parâmetros 5 e 1, retornando 5.</li>
<li>É identificada a <em>last call</em> <code>fact/2</code> com os parâmetros 4 e 5, portanto <code>fact(5, 1)</code> é desempilhado, assim como suas variáveis.</li>
<li>4 é diferente de 0, então caímos na segunda assinatura de <code>fact/2</code>, onde 4 é vinculado a <code>N</code> e 5 é vinculado a <code>Acc</code>.</li>
<li>Neste ponto temos na pilha: <code>fact(4, 5)</code>, <code>N = 4</code> e <code>Acc = 5</code>.</li>
<li>É executada a função <code>erlang:'-'/2</code> com os parâmetros 4 e 1, retornando 3.</li>
<li>É executada a função <code>erlang:'*'/2</code> com os parâmetros 4 e 5, retornando 20.</li>
<li>É identificada a <em>last call</em> <code>fact/2</code> com os parâmetros 3 e 20, portanto <code>fact(4, 5)</code> é desempilhado, assim como suas variáveis.</li>
<li>3 é diferente de 0, então caímos na segunda assinatura de <code>fact/2</code>, onde 3 é vinculado a <code>N</code> e 20 é vinculado a <code>Acc</code>.</li>
<li>Neste ponto temos na pilha: <code>fact(3, 20)</code>, <code>N = 3</code> e <code>Acc = 20</code>.</li>
<li>É executada a função <code>erlang:'-'/2</code> com os parâmetros 3 e 1, retornando 2.</li>
<li>É executada a função <code>erlang:'*'/2</code> com os parâmetros 3 e 20, retornando 60.</li>
<li>É identificada a <em>last call</em> <code>fact/2</code> com os parâmetros 2 e 60, portanto <code>fact(3, 20)</code> é desempilhado, assim como suas variáveis.</li>
<li>2 é diferente de 0, então caímos na segunda assinatura de <code>fact/2</code>, onde 2 é vinculado a <code>N</code> e 60 é vinculado a <code>Acc</code>.</li>
<li>Neste ponto temos na pilha: <code>fact(2, 60)</code>, <code>N = 2</code> e <code>Acc = 60</code>.</li>
<li>É executada a função <code>erlang:'-'/2</code> com os parâmetros 2 e 1, retornando 1.</li>
<li>É executada a função <code>erlang:'*'/2</code> com os parâmetros 2 e 60, retornando 120.</li>
<li>É identificada a <em>last call</em> <code>fact/2</code> com os parâmetros 1 e 120, portanto <code>fact(2, 60)</code> é desempilhado, assim como suas variáveis.</li>
<li>1 é diferente de 0, então caímos na segunda assinatura de <code>fact/2</code>, onde 1 é vinculado a <code>N</code> e 120 é vinculado a <code>Acc</code>.</li>
<li>Neste ponto temos na pilha: <code>fact(1, 120)</code>, <code>N = 1</code> e <code>Acc = 120</code>.</li>
<li>É executada a função <code>erlang:'-'/2</code> com os parâmetros 1 e 1, retornando 0.</li>
<li>É executada a função <code>erlang:'*'/2</code> com os parâmetros 1 e 120, retornando 120.</li>
<li>É identificada a <em>last call</em> <code>fact/2</code> com os parâmetros 0 e 120, portanto <code>fact(1, 120)</code> é desempilhado, assim como suas variáveis.</li>
<li>0 casa com a primeira assinatura da função <code>fact/2</code>, portanto 120 é vinculado a <code>Acc</code>.</li>
<li>Neste ponto temos na pilha: <code>fact(0, 120)</code> e <code>Acc = 120</code>.</li>
<li>A função retorna 120, que é consumido pela chamada original.</li>
</ul><br/>
Repare que a pilha permaneceu com tamanho constante por todo o processo. É possível executar <code>fact(200)</code> sem estourar a pilha, aumentando apenas o tempo de processamento.<br/><br/>
Esta é então a dica para a programação de <em>loops</em> em Erlang: use funções <em>tail recursive</em>, que são aquelas cuja chamada da recursão (da própria função) é a última do procedimento, e armazena a resposta em um acumulador em vez de aguardar o retorno de cada reiteração para processar o próximo resultado.<br/><br/>
[]’s<br />
Cacilhας, La Batalemaℭacilhας, ℒa ℬatalemahttp://www.blogger.com/profile/14265747724618147106noreply@blogger.com0