You are currently browsing the archives for the scala category


Quer saber onde será seu próximo trabalho?

Então não deixe de visitar…

O site é recém-nascido, mas já tem uns recursos bem legais, como sistema de pesquisa por palavras-chave, núvem de tags e entre outros. Vale a pena conferir e acompanhar sua evolução – e oportunidades de bons trabalhos.

Mais uma iniciativa bem interessante da Caelum. :)

Sim, programação funcional é relevante hoje

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 nesse 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!

Mais diversão com Scala

Uma das coisas que mais tenho estudado ultimamente é a integração entre linguagens de programação – principalmente com Java -, de maneira a extrair o melhor de cada uma delas, o mais transparentemente possível. Scala, tal como JRuby, tem me proporcionado isso de maneira fantástica.

Scala tem total integração com Java, uma de suas plataforma host (a outra é o Microsoft .Net Framework). Assim, pode-se usar classes e interfaces de bibliotecas Java de forma natural. Vejamos um exemplo bem simples:


import java.util.{Date, Locale}
import java.text.SimpleDateFormat

object ExibeDataFormatada {
  def main(args: Array[String]) {
    val now = new Date
    val formatter = new SimpleDateFormat(
      "EEEE, dd 'de' MMMM 'de' yyyy")

    // método com apenas um parâmetro podem ser invocados
    // com sintaxe infix
    println(formatter format now)
  }
}

Este código, certamente, é bem familiar para qualquer programador Java. O que ele faz é:

1. Importar as classes Date e Locale do pacote java.util, bem como a classe SimpleDateFormat do pacote java.text;
2. Criar um objeto ExibeDataFormatada, que é um pequeno aplicativo Scala, e definir um método main, dentro do qual o aplicativo executará;
3. Criar dois val‘s (valores imutáveis): now para a data atual do sistema, e formatter para formatar nossa data atual;
4. Invocar o método format do objeto formatter, passando-lhe como parâmetro now, que é a data atual.

(Se quiser rodar esse código, veja este post.)

Você deve ter notado que Scala trabalha com classes Java de maneira totalmente natural. Na verdade, muitas classes Scala fazem wrap de classes Java e as melhoram – como as classes com prefixo Rich.

Este foi um exemplo muito simples mesmo, mas creio que já deu para você ver que coisas muito sofisticadas também podem ser feitas com a mesma naturalidade.

Acredito que a integração entre linhagens é o que pode alavancar muitos projetos de requisitos complexos e totalmente heterogêneos. Porque sempre há algo que se pode fazer melhor e mais barato em uma linguagem do que em outra. Só é preciso tomar cuidado para não acabar criando uma Torre de Babel.

E você, o que pensa disso?

Um pouco de diversão com Scala

Scala é uma linguagem de programação muito flexivel, que possibilita conceber construções extremamente sofisticadas, o que facilita bastante a criação de DSLs. Ela combina dois poderosos paradigmas: Programação Orientada a Objetos e Programação Funcional. Tudo em Scala é um objeto, inclusive, funções. Ela não é a única que faz isso, mas vem ganhando aplausos pelo seu design sofisticado. Na verdade, Scala foi inspirada em muitas linguagens – Java, C++, Smalltalk, Eiffel, OCaml, F#, Haskell, Erlang.

Scala também possui um ótimo modelo de programação concorrente, inspirado nos poderosos atores de Erlang.

Não bastasse tudo isso, Scala é open source e possui implementações para a plataforma Java e .NET.

Uma das coisas que mais gosto em Scala é sua natureza funcional. Não que eu seja um mestre da programação funcional. Mas este é um paradigma que tenho aprendido a apreciar bastante.

Sobre esse extenso assunto, quero fazer uma pequenina citação a “funções”.

Uma função em Scala é um first-class value. Como qualquer outro valor, uma função pode ser passada por parâmetro para outra função, bem como ser retornada como resultado. Funções que recebem outras funções como parâmetro ou retornam como resultado são chamadas de higher-order function. Isso dá um flexibilidade impressionante!

Um exemplo?

object Calculo {
  def soma(func: Int => Int, a: Int, b: Int): Int =
    if (a == 0 || b == 0) func(10) else a + b

  def main(args: Array[String]) {
    println("Ex1: " + soma((x: Int) => x + 100, 0, 0))
    println("Ex2: " + soma((x: Int) => x + 100, 10, 20))
  }
}

Este é um programinha bastante simples. O que ele faz é criar um objeto Calculo, que funciona como uma instância singleton, e executá-o a partir do método main – semelhantemente ao que acontece em Java.

Além do método main, lá está nossa função soma. Ela é uma função simples de soma. Bem, não tão simples assim. Ela recebe uma função anonima por parâmetro (func) e, caso a ou b seja zero, ela a usa passando 10 como parâmetro.

Se quiser rodar este programinha e ver o resultado de sua execução, basta:

1- Instalar a versão de Scala para seu SO;
2- Salvar esse código em um arquivo Calculo.scala;
3- Compilar esse arquivo com scalac Calculo.scala;
4- Executar com scala Calculo.

Scala é uma linguagem fantástica. Quando mais a conheço, mais a aprecio!