Páginas

Showing posts with label racket. Show all posts
Showing posts with label racket. Show all posts

Sunday, February 5, 2012

Conversão de unidades com Racket

Um rápido post para compartilhar um simples conversor de unidades escrito em Racket.
Resolvi escrever depois de ver a ideia de usar unidades junto dos valores no tutorial oficial do Erlang.

No exemplo, vamos converter centímetros em polegadas ou vice-versa. É fácil estender a ideia para converter outras unidades, como temperatura, pressão, moeda, etc.

O principal é só isso aqui:

(define (convert-length value)
  (match value
    [`(,(? number? v) centimeter) `(,(* v 2.54) inch)]
    [`(,(? number? v) inch) `(,(/ v 2.54) centimeter)]))

Ou seja, criamos uma função chamada convert-length que recebe um valor. O interessante é que esse valor não é um tipo numérico, mas sim uma estrutura de dados que contém um valor numérico e uma unidade.
Com isso, podemos ter uma única função de conversão, e sabemos sempre exatamente com que unidade estamos trabalhando.

O que é feito na função é usar casamento de padrões (pattern matching), uma funcionalidade padrão do Racket e bastante poderosa para trabalhar com estruturas de dados, para realizar a conversão apropriada de acordo com o valor de entrada.

[`(,(? number? v) centimeter) ; padrão
 `(,(* v 2.54) inch)] ; valor retornado

O primeiro padrão casa com uma lista formada por um número, armazenado na variável v, e o símbolo literal centimeter. A segunda parte da cláusula computa a conversão e cria uma estrutura com a nova unidade de medida.

O código completo:

#lang racket
(require rackunit)

;; Idea from the Erlang Tutorial
;; http://www.erlang.org/doc/getting_started/seq_prog.html#id64621
(define (convert-length value)
  (match value
    [`(,(? number? v) centimeter) `(,(* v 2.54) inch)]
    [`(,(? number? v) inch) `(,(/ v 2.54) centimeter)]
    [_ (error "Wrong value format. Value must be a list of two elements: a number and an unit, inch or centimeter.")]))

;; From Matthias Felleisein
;; http://lists.racket-lang.org/users/archive/2011-November/049154.html
(define (tee tag v)
  (displayln `(,tag ,v))
  v)

;;----------------------------------------------------------------------
;; Tests
(check-equal?
 (tee 'test-1 (convert-length '(1 centimeter)))
 '(2.54 inch))

(check-equal?
 (tee 'test-2 (convert-length '(2.54 inch)))
 '(1.0 centimeter))

(check-equal?
 (tee 'test-3 (convert-length (convert-length '(1 centimeter))))
 '(1.0 centimeter))

(check-exn exn:fail?
 (λ ()
   (convert-length 3.4)))

Thursday, September 15, 2011

Perl, Ruby, Python & Racket: time matters

Estava aqui pensando em duas coisas:

  1. Qual o comportamento de diversas linguagens de programação quando fazemos um "import" ou "require", e o que acontece se um mesmo arquivo for requirido várias vezes na árvore de dependências.
  2. Qual o tempo que leva para executar um script mínimo.
A motivação vem da diferença que dá usar #lang racket x #lang racket/base em Racket. Quando usamos a linguagem completa, temos todas as baterias em nossas mãos, e como penalização carregamos um monte de código pra memória sem que este seja efetivamente necessário. A segunda opção é mais leve, tem apenas definido elementos mais centrais da linguagem, ideal para usar quando estamos criando nossas bibliotecas.

Há uns anos atrás já havia feito experimentos similares (provavelmente não documentados) com Python. Agora fiz pequenos scripts em Python, Racket, Ruby e Perl para comparar. Atenção não leve em consideração os números deste post como "benchmarks" ou classificadores/qualificadores de uma ou outra linguagem.

O procedimento experimental

Para reproduzir este experimento, crie 4 diretórios:
mkdir t{python,ruby,racket,perl}
(Não entendeu a linha acima? Veja meu post sobre o uso de chaves no Bash)

Em cada um, crie 3 arquivos, "a", "b" e "c", com a extensão da respectiva linguagem.
O resultado final fica assim:

./tperl
├── a.pl
├── b.pl
└── c.pl
./tracket
├── a.rkt
├── b.rkt
└── c.rkt
./truby
├── a.rb
├── b.rb
└── c.rb
./tpython
├── a.py
├── b.py
└── c.py

Cada arquivo contém:
tpython/a.py
::::::::::::::
print "a"

tpython/b.py
::::::::::::::
import a
print "b"

tpython/c.py
::::::::::::::
import a, b
print "c"

Para as outras linguagens é similar, veja:

c.pl (Perl)

require "a.pl";
require "b.pl";
print "c\n";
c.rkt (Racket)
#lang racket/base
(require "a.rkt" "b.rkt")
(displayln "c")
c.rb (Ruby)
require 'a.rb'
require 'b.rb'
puts 'c'

Resultado 1

Todas as 4 linguagens parecem ser consistentes em:
  1. executar todo o código do corpo de um arquivo importado (incluindo efeitos-colaterais)
  2. não re-executar código já importado anteriormente (mesmo que por dependência indireta)
Ou seja, o resultado visual da execução de todos os exemplos é:

a
b
c

Resultado 2

Entretanto, o tempo de execução é bem diferente. Usando o time, os melhores resultados encontrados após muitas execuções num Core2Duo 2.2GHz com Ubuntu 10.10 64bits:

time perl c.pl
real 0m0.007s
user 0m0.000s
sys 0m0.000s

time ruby c.rb
real 0m0.010s
user 0m0.000s
sys 0m0.000s

time python c.py
real 0m0.015s
user 0m0.010s
sys 0m0.000s

time racket c.rkt
real 0m0.084s
user 0m0.060s
sys 0m0.020s

Se compilarmos o código Racket usando o "raco make", temos:

raco make c.rkt
time racket c.rkt

real 0m0.053s
user 0m0.030s
sys 0m0.020s


Conclusão
  • Racket e Python permitem fazer importação de vários módulos num único comando, enquanto que Ruby e Perl não. (Sim, existe o gem require_all pro Ruby, e certamente existe algo similar pro Perl no milagroso CPAN -- mas pelo que sei não existe solução "built-in" na linguagem)


  • Meus amigos Perl Monges devem ficar felizes porque Perl despontou como o mais rápido, né  Breno, Diogo, Samir, Ronald, e cia?
  • Meus amigos adeptos do Ruby vão ficar felizes e dizer que Ruby é mais rápido do que Python :P
  • Meus amigos Pythonistas, pé no chão, vão concordar que Python é rápido o suficiente e é mais divertido que Ruby (e que a conclusão acima, dos rubistas, não pode ser considerada já que meus resultados não provam nada...)
  • Meus amigos que ainda estão conhecendo Racket podem fazer caretas, normal... não tô nem aí :)
    Não me importo em "pagar o preço" para programar numa linguagem mais poderosa e bonita.

Obs: como as diferentes linguagens usam diferentes terminologias, perdoem o uso nem sempre preciso de "módulo", "arquivo", "importar", "requerer", etc. Espero não causar ambiguidade para o leitor.

Monday, August 1, 2011

Racket com readline


Para quem estava acostumado ao IPython, usar o interpretador do Racket no terminal pode ser um bocado decepcionante.

Isto porque por padrão o REPL é bem rudimentar, sem suporte a auto-completar, sem histórico, sem nada...

O que existe entretanto é um problema com licenças. O readline é distribuído em GPL, e o Racket em LGPL, e para não haver conflitos o suporte a readline vem desativado por padrão. Mas ele está lá.

A documentação em inglês dá os detalhes completos: Readline: Terminal Interaction.
Este módulo vai tornar sua experiência no REPL muito mais agradável, naqueles momentos em que você está no terminal e não quer abrir o DrRacket ou o Emacs.

Para usar basta iniciar o racket assim:

  racket -il readline

E se você não quiser ter que fazer isto toda vez, basta instalar permanentemente o suporte ao readline chamando uma função :D


Pronto. Agora toda vez que executar racket você entratá num REPL com histórico (que lembra inclusive as sessões anteriores), auto-completar usando tab, seta pra cima e pra baixo pra navegar nos comandos, etc.

Para ficar melhor ainda, adicione uma linha no arquivo ~/.inputrc:

set blink-matching-paren on

Esta sugestão do Eli Barzilay faz com que seu terminal indique qual "(" está relacionado com qual ")" quando você digita, e funciona tanto dentro do racket quanto em qualquer outro canto, inclusive no IPython. Também funciona com [] e {}.

E não pára por aí... o REPL vai ficar melhor ainda com o XREPL que vem aí na próxima release.
Com ele será possível fazer coisas já corriqueiras no IPython, agora em Racket.

Happy hacking!

Tuesday, July 19, 2011

Escolhendo um Lisp: do Clojure ao Racket

Graças a um email de um amigo, o Lucas Teixeira, finalmente escrevi algumas coisas que já vinha comentando com algumas pessoas, geralmente nos pós-dojos.

Era pra ser um email pro Lucas, mas acabei expressando coisas que poderiam ficar públicas.

Bem, ele começou dizendo no email:
Então... sempre quis aprender programação funcional. Já tentei Haskell, LISP, Scheme, mas nunca pegou de verdade.

Tô tentando aprender Clojure agora. Baixei o Clojure Box e uns tutoriais da Internet. Tô resolvendo uns problemas do Project Euler e o clojure-koans.

Tem alguma dica de material?

Que tipo de coisa você tá / tava fazendo com Clojure?
Cara, foi muito surpreendente seu email.

Vamos a um apanhado de impressões sobre algumas linguagens da família lisp, começando com Clojure, passando por Common Lisp, Scheme e chegando em Racket.

Descrevendo objetos com Racket

O Racket é muito esperto, e com o auxílio de um módulo disponível no PLaneT é possível fazer coisas bem divertidas, como fazer contas:

#lang racket
(require (planet williams/describe/describe))

(displayln
 (string-join
  (map (λ (t) ((if (exact-integer? t)
                   integer->string
                   (curry format "~a")) t))
       `(I will show you how Racket knows how to count.,"\n"
           Racket knows that 3 + 4 is ,(+ 3 4),"\n"
           Racket knows that 5 * 9 is ,(* 5 9),"\n"
           and that 5 / 4 is ,(/ 5 4),"\n"
           and 2 ^ 10 is ,(expt 2 10),"\n"
           and much more...))
  " "))

(define (! n)
    (if (= n 0)
        1
        (* n (! (sub1 n)))))
(describe (- (! 40) (! 41)))

Tão esperando que pra instalar o Racket e ver o output?
(Alias, que tal implementarmos um "describe" no dojo?)

Veja a documentação do describe pra ver o que mais ele pode fazer...

Friday, June 10, 2011

Brainfuck com Racket

Esta é uma novidade fresquinha. O Danny Yoo está desenvolvendo uma versão de Brainfuck que roda na infraestrutura do Racket, para mostrar que é possível ter linguagens com sintaxe totalmente diferente de Lisp. Ele chamou a linguagem de Brainfudge, e o código está disponível no github.

Como podemos ver, o Racket é uma linguagem para escrever linguagens.

Para os curiosos de plantão, aqui vai um Hello World:

#lang planet dyoo/brainfudge

+++++ +++++             initialize counter (cell #0) to 10
[                       use loop to set the next four cells to 70/100/30/10
    > +++++ ++              add  7 to cell #1
    > +++++ +++++           add 10 to cell #2 
    > +++                   add  3 to cell #3
    > +                     add  1 to cell #4
    <<<< -                  decrement counter (cell #0)
]                   
> ++ .                  print 'H'
> + .                   print 'e'
+++++ ++ .              print 'l'
.                       print 'l'
+++ .                   print 'o'
> ++ .                  print ' '
<< +++++ +++++ +++++ .  print 'W'
> .                     print 'o'
+++ .                   print 'r'
----- - .               print 'l'
----- --- .             print 'd'
> + .                   print '!'
> .                     print '\n'

Como de costume, não é preciso instalar nada manualmente nem mesmo salvar o arquivo! Vejam:



Friday, June 3, 2011

Comunidade Racket em português

O Racket tem uma comunidade bastante ativa e receptiva.

Para abrir espaço para aqueles a fim de aprender um pouco mais sobre Racket, mas que tem dificuldades de se comunicar em inglês, criei o grupo Racket Brasil.

Apesar do nome, fica o convite e apelo à participação dos nossos amigos portugueses e demais falantes da nossa língua.

É a oportunidade de nos conhecermos melhor e trocar informações.

Sunday, May 29, 2011

Programando para Android com Racket

Numa possível "série" de posts que acaba de começar agora, vou mostrar as várias possibilidades de uso de Racket, a linguagem para criar linguagens.

Uma das coisas fantásticas de Racket é a documentação. Esta pode ser consultada online ou offline quando você instala o ambiente na sua máquina (existem instaladores para Windows, Linux e Mac OS X).

A instalação é fácil veja meu post para mais detalhes. Para escrever nosso programa para Android ou browser vamos usar o Moby, um compilador da linguagem Advanced Student Language (uma das linguagens do Racket) para Javascript/mobile.

Não precisa se preocupar com a instalação do Moby. Ele está disponível no PLaneT, o sistema de distribuição de pacotes do Racket. Isto quer dizer que o DrRacket (uma IDE que vem incluída) vai instalar o Moby pra você no primeiro uso e deixar tudo prontinho...

Ok, então você instalou o Racket, abriu o DrRacket, e agora?
Como sempre, muito fácil.

Como instalar o Racket

Neste post explico como instalar o Racket, incluindo os programas e utilitários de linha de comando e a IDE DrRacket.

Para começar, acesse a página de download do Racket, escolha sua plataforma, e clique no botão de download.

Thursday, May 26, 2011

Mergulhando no Racket

Se tudo der certo vou escrever ainda muitos posts sobre Racket aqui no blog.
Simplesmente porque se eu achava Python muito legal, hoje Racket parece ser o novo Python na minha vida.

Continuo achando Python muito legal, mas acho que o problema é que muitos outros também, e isto tem tornado Python "a linguagem da vez" em algumas situações (muitas vezes acompanhados de Django), com trágicas consequências.

Talvez seja exagero meu, mas meu ouvido já doeu bastante ao ouvir alguns escrevendo "php em Python", pessoas que não entendem nem de PHP, nem de Python, nem de Web e nem de programação em níveis mais básicos.

Não estou aqui para reclamar disto, mas sim para fazer uma breve introdução à mudança - ou ao acréscimo de mais uma linguagem legal ao repertório.

Ah, os posts começaram quando falei sobre minha Introdução ao Racket no Coding Dojo Rio.

E dentro de alguns minutos terá mais um...

Wednesday, May 18, 2011

Introdução ao Racket no Coding Dojo Rio

Hoje no Dojo Rio no Centro farei uma apresentação de introdução à linguagem Racket.
Fiz um post no blog do Dojo Rio e replico ele aqui:

O que é “Racket”?
É uma linguagem relativamente nova, antes chamada PLT Scheme, que mostra sua origem em Scheme, um dos dois mais conhecidos dialetos de Lisp (o outro sendo Common Lisp).

Racket pode ser considerado também como uma família de linguagens, já que existem diversas sublinguagens para fazer as mais diversas coisas, como escrever documentação, apresentação de slides, ensinar programação, programação em lógica, etc.

Por que esta apresentação?
Já faz um tempo que queria compartilhar meu entusiasmo com programação funcional e Lisp, e por vezes pensei em levar lá pro Dojo o Common Lisp. Entretanto, a forma mais legal de trabalhar com CL seria usando o editor Emacs e o SLIME.

Acontece que configurar tudo isso e esperar que as pessoas consigam usar numa boa é complicado — principalmente esta segunda parte. Já basta a resistência com a sintaxe diferente e com ideias e formas de programar diferentes, ainda ter que lidar com um ambiente “hostil” certamente traria desânimo, revolta e incompreensão.

Se você já está habituado a usar o Emacs, programar em qualquer dialeto de Lisp certamente vai ser “mamão-com-açúcar”!

Por que Racket?
Então, por que Racket? O Racket além de funcionar bem em Linux, Mac OS e Windows, vem com um ambiente de desenvolvimento, oDrRacket, que torna a experiência de programar divertida e produtiva (ymmv). E mais, a documentação é muito boa, e a comunidade muito receptiva (você sempre pode tirar dúvidas via IRC ou lista de emails).
Screenshot do DrRacket
Screenshot do DrRacket

Racket não é só uma linguagem educacional! Também é possível fazer aplicações reais, em diversas áreas, e elas existem. Abaixo uma lista de alguns usos de Lisp/Scheme/Racket: