Meu último post aqui!

Sim, este é meu último post aqui. Mas não o último da minha vida! :)

O que acontece é que acabei de me mudar para casa própria:

leandrosilva.com.br

Espero ver todos vocês por lá!

Ah! Não se esqueçam de atualizar o RSS.

Update (18-11-08): Eu tinha feito a besteira de colocar o blog no /codezone, mas depois voltei à sanidade e resolvi botar na raíz do domínio mesmo. I’m sorry!

Sim, programação funcional é relevante hoje

[Novo endereço: leandrosilva.com.br.]

Há um tempo tenho me interessado pelo paradigma de programação funcional, estudado e tentado aplicar vez ou outra algum de seus conceitos que faça sentido no domínio do problema que estou tentando resolver.

Com base nisso, resolvi escrever este post para dizer que, sim, programação funcional é relevante hoje, tanto quanto foi ontem – se não um pouco mais; e também dar uma visão geral sobre alguns de seus conceitos.

O que é programação funcional?

Segundo a definição de Paul Hudak em seu paper de 1989, “Conception, evolution, and application of functional programming languages”:

Programação funcional é um paradigma de programação que trata a computação como uma avaliação de funções matemáticas e que evita estados ou dados mutáveis. Ela enfatiza a aplicação de funções, em contraste da programação imperativa, que enfatiza mudanças no estado do programa.

Assim, praticar programação funcional consiste em definir funções e usar o computador como um avaliador de expressões. Aliás, uma característica predominante da programação funcional é que o significado de uma expressão é o seu valor, e o papel do computador é obtê-lo através da avaliação da expressão. Por exemplo, considere a expressão 2 + 3. Qual é o seu significado? 5. Agora, considere a expressão (2 x 2) + 1. Qual é o seu significado? 5. Ou seja, a avaliação nos faz concluir que as duas expressões significam a mesma coisa.

Outra característica básica e fundamental em linguagens funcionais é que funções são valores de primeira importancia, podendo estas serem usadas como parâmetro ou retorno de outras funções. Além do que, funções também são avaliadas como qualquer outra expressão matemática.

Aplicação do paradigma funcional

Programação funcional, obviamente, pode ser aplicada para resolver problemas de domínio matemático, mas não somente isso. Absolutamente!

Atualmente, muito do revival – se é que posso dizer assim – do paradigma de programação funcional se deve a aplicação dela no campo da concorrência, do processamento paralelo. Isso por conta de sua natureza stateless. É nesse campo que estão os grandes méritos de Erlang, e a motivação de F# e Scala. (Se bem que Scala pode, sim, trabalhar com estados. Quando a F#, eu não sei. Mas isso não importa muito agora.)

Há pouco ouvi falar também sobre uma bibliotéca fantástica para construção de interfaces gráficas escrita em Haskell, mas sinceramente nunca testei. (Na verdade, nunca escrevi uma só linha de código em Haskell.)

Exemplos de linguagens funcionais

Existe uma pancada uma grande número de linguagens funcionais, talvez muito mais do que você possa imaginar. Apenas para citar algumas: Lisp, Haskell, Scheme, XSTL, OCaml, Erlang, F# e Scala. Mas, acredite, há muitas outras!

Conceitos funcionais em código

Como esse é um blog de programação, e estamos falando de programação, quero explicar rapidamente alguns conceitos de programação funcional exemplificando em código.

1- Lambda Calculus

O principal fundamento da programação funcional é a teoria Lambda Calculus, cuja qual podemos encontrar a seguinte definição na Wikipedia:

In mathematical logic and computer science, lambda calculus, also written as λ-calculus, is a formal system designed to investigate function definition, function application and recursion. It was introduced by Alonzo Church and Stephen Cole Kleene in the 1930s as part of an investigation into the foundations of mathematics, but has emerged as a useful tool in the investigation of problems in computability or recursion theory, and forms the basis of a paradigm of computer programming called functional programming.[1]

The lambda calculus can be thought of as an idealized, minimalistic programming language. It is capable of expressing any algorithm, and it is this fact that makes the model of functional programming an important one. Functional programs are stateless and deal exclusively with functions that accept and return data (including other functions), but they produce no side effects in ‘state’ and thus make no alterations to incoming data. Modern functional languages, building on the lambda calculus, include Erlang, Haskell, Lisp, ML, Scheme, Scala and F#.

Entendemos então que, em programação funcional, funções são abordadas no puro sentido matemático. A definição da Wikipedia para Lisp diz:

Lisp é uma família de linguagens de programação concebida por John McCarthy em 1958. Num célebre artigo, ele mostra que é possível usar exclusivamente funções matemáticas como estruturas de dados elementares (o que é possível a partir do momento em que há um mecanismo formal para manipular funções: o Cálculo Lambda de Alonzo Church).

Via de regra, toda linguagem funcional oferece algum tipo de construção para cálculo lambda.

Por exemplo, considere a seguinte função matemática:

f(x) = x + 30

Em Scala, ela poderia ser escrita assim:

val f = (x: Int) => x + 30
f(5)   // 35

Ou mesmo em Ruby, que apesar de não ser funcional, oferece suporte a algumas abordagens desse paradigma, poderia ser escrito assim:

f = lambda {|x| x + 30}
f[10]   # 40

2- High-order function

High-order functions são funções que podem receber outras funções como parâmetro, e também retorná-las como resultado. A estas damos o nome de função de primeira classe. Essa é uma característica extremamente importante em linguagens funcionais. Vejamos um exemplo:

def escolhido(a: Int, b: Int): Int = if (a >= b) a else b

def imprEscolhido(f: (Int, Int) => Int, a: Int, b: Int) =
  println("O escolhido foi: " + f(a, b))

...

// usando a função escolhido
imprEscolhido(escolhido, 1, 5)   // 5

// usando uma função anônima
imprEscolhido((x: Int, y: Int) => x, 12, 2)   // 12

2- Currying

Currying é a técnica de transformar uma função que recebe multiplos argumentos de maneira que ela possa ser chamada como uma cadeia de funções, com apenas um argumento por vez. Na prática, o que acontece é que a cada chamada a uma função da cadeia, uma nova função é retornada.

Vamos ver um exemplo que pode ser encontrado na integra no site A Tour of Scala:

// cria uma função para filtrar uma lista
def filter(xs: List[Int], p: Int => Boolean): List[Int] =
  if (xs.isEmpty) xs
  else if (p(xs.head)) xs.head :: filter(xs.tail, p)
  else filter(xs.tail, p)

// cria uma função "módulo" para ser usada no filtro,
// por isso ela retorna "true" ou "false"
def modN(n: Int)(x: Int) = ((x % n) == 0)

// cria uma lista com números de 1 a 8
val nums = List(1, 2, 3, 4, 5, 6, 7, 8 )

// imprime aplicando módulo em 2
println(filter(nums, modN(2)))   // List(2,4,6,8)

// imprime aplicando módulo em 3
println(filter(nums, modN(3)))   // List(3,6)

Se você não está familiarizado com código Scala, não se preocupe, à primeira vista parece meio esquisito mesmo. Por isso, não se atente aos detalhes. O importante aqui é você entender que a saída desse programa depende:

1º) Do número que é aplicado ao primeiro argumento (n) da função modN, quanto ela é chamada e o seu resultado passado como argumento à função filter – pois o seu resultado será uma “nova função” que receberá apenas o segundo argumento (x) que ela definiu;

2º) Do número que a função filter aplica ao único argumento que a função p (que é resultado da chamada a modN) aceita.

Ou seja, é como se a função modN tivesse seus dois argumentos parcialmente informados em dois momentos diferentes, tornando a sua chamada muito mais simples e flexível. Essa é a idéia da cadeia.

Vamos um ver outro exemplo, ainda em Scala, talvez um pouco mais simples:

// cria uma função que retorna "outra função" que recebe
// apenas o segundo argumento desta
def idadeAceita(m: Int)(i: Int): Boolean = i <= m

// ao ser chamada, a função idadeAceita retorna uma "nova
// função" que dei o nome de aplicarIdade e recebe apenas
// o segundo argumento definido por idadeAceita
val aplicarIdade: (Int) => Boolean = idadeAceita(18)

...

aplicarIdade(14)   // true
aplicarIdade(40)   // false

Acho que esse exemplo fala por si e dispensa maiores explicações. :)

Não é interessante como os diversos conceitos abordados até aqui vão se completando?

Que mais?

Bem, tudo que eu disse nesso post gigante é apenas uma visão geral. Talvez a pontinha do iceberg. Então espero que ele te motive a estudar um pouco mais sobre programação funcional. (O texto está repleto de links para outros texto interessantes.)

Valeu!

Como está seu marketing pessoal?

[Novo endereço: leandrosilva.com.br.]

Bruno Pereira escreveu dois posts (esse e esse) muito relevantes sobre marketing pessoal, em especial, para desenvolvedores de software, que eu não poderia deixar de citar e sugerir aqui em meu blog.

Ler esses posts me fez lembrar do keynote de Chad Fowler na Rails Summit sobre tornar-se uma pessoa brilhante. Facinante!

É isso ai, fica aqui a dica…

Seja brilhante!!!

Acho que Ola Bini não dorme!

[Novo endereço: leandrosilva.com.br.]

Ola Bini publicou hoje em seu blog um roadmap para sua mais nova criação, a linguagem de programação Ioke.

Ioke é, nas palavras do próprio Ola Bini, uma lingagem de programação fortemente tipada, orientada a objetos baseada em protótipos, bastante inspirada em Io, SmallTalk, Self, Ruby e Lisp (especialmente Common Lisp). Atualmente, ela está implementada em Java e rodar unicamente na JVM.

Nesse roadmap, Ola Bini anuncia que a primeira release será chamada 0 (sim, zero), e deverá ser publicada até no máximo o Natal.

Se você quiser acompanhar a evolução de Ioke, você pode segui-la no GitHub.

Agora fica a pergunta: Esse Ola Bini não dorme, não?

O que achei do workshop de DDD da Caelum?

[Novo endereço: leandrosilva.com.br.]

Hoje participei do workshop de Domain-Driven Design que a Caelum promoveu junto com Phillip Calçado, consultor da ThoughtWorks.

O workshop foi excelente. Muito dinâmico, com conteúdo bastante abrangente, e muita mão-na-massa. Aliás, não tivemos nem computador. Fizemos tudo em cartões pautados, CRC-like, no melhor estilo free style!!!

Tenho praticado DDD há aproximadamente 1 ano e meio, na CVC Turismo, e confesso que ainda carregava comigo algumas dúvidas, tanto de abordagem quanto de implementação. Porque DDD não se aprende do dia pra noite, nem decorando um conjunto de padrões. DDD é muito mais do que isso. DDD é, fundamentalmente, sobre “melhorar a comunicação entre os envolvidos num projeto”. Incrível!

Com certeza esse é um treinamento que recomendo de mais. (Principalmente àqueles que vivem atormentados por DAOs e repositórios…. kkk)

Brincadeiras à parte, se você é um desenvolvedor sério, preocupado em produzir software de qualidade, que realmente atenda às expectativas do cliente, você precisa participar desse workshop.

Mais uma vez, ao Phillip e à Caelum, parabéns!

(Ah! Paulôôô, o coffe-break, como sempre, fantástico!)

Rails Summit, o melhor evento que já participei!

[Novo endereço: leandrosilva.com.br.]

A Rails Summit Latin America foi o melhor evento de tecnologia que já participei até hoje. Simplesmente, excelente!

O meu destaque fica para as apresentações de Chad Fowler e Obie Fernandez.

Quem estiver interessado, aqui tem uma trilha legal do evento.

Se você perdeu esse ano, pel’amor, não perca ano que vem não!

Parabéns ao Akita e à Locaweb…

Intuitividade de Ruby

[Novo endereço: leandrosilva.com.br.]

Uma das coisas que mais gosto em Ruby é que ela é uma linguagem muito expressiva e intuitiva.

Quer ver um exemplo? Pois bem…

Suponha que você queira saber se uma determinada classe é filha de outra, como você faria?

irb(main):001:0> Integer < Fixnum
=> false

Logo, Integer não é filha de Fixnum. Mas, e o contrario, será que é verdadeiro?

irb(main):002:0> Integer > Fixnum
=> true

Sim, Fixnum é filha de Integer.

Percebeu a intuitividade? Ainda não? Vamos lá então…

Para dizer que uma classe é filha de outra, em Ruby, usamos o operador < (menor), pois a classe filha passará a ocupar um lugar hieraquicamente abaixo de sua classe mãe.

class Filha < Mae
  ...
end

Assim, nada mais intuitivo do que testar a posição hierarquica de uma classe em relação a outra usando os operadores > (maior) e < (menor).

E agora, que tal? É ou não é intuitiva?