Thursday, September 11, 2014

Fatorial em Scala

Focando um pouco na linguagem Scala, comecei a definir algumas funções matemáticas para explorar a natureza funcional, assim como minhas experiências em Haskell. Para aprender um pouco de Haskell, pesquiso por alguma fórmula matemática na wikipedia e traduzo na linguagem funcional.

Exemplo: http://en.wikipedia.org/wiki/Factorial

A definição formal é dada por:


Isso é fácil de traduzir para Haskell:

fact 0 = 1
fact n = n * fact (n - 1)

Em duas linhas a implementação fica aderente à definição matemática. Pode-se utilizar em funções de probabilidade tais como Arranjo:

arranjo n p = fact n / fact (n - p)

No entanto, conhecemos essas fórmulas de uma maneira mais natural como:

A(n,p) = n! / (n - p)!

Em Scala é possível utilizar a notação ! para fatorial, utilizando métodos implícitos. O trecho de código abaixo mostra como fazer isso:

[AdvancedMath.scala]
package factorial

class AdvancedMath {
    def factorial(a: Long):
        Long = if (a == 0) 1 else a * factorial(a - 1) //1
}

object AdvancedMath extends AdvancedMath {
  implicit def AdvancedMath = new AdvancedMath
}

[meuTesteFatorial.sc]
package myBulkScalaProject;

object meuTeste {

  implicit class AddFact(val num: Long) extends AnyVal { //2
    def ! = AdvancedMath.factorial(num) //3
  }

  def arranjo(n:Long, p:Long):
      Long = (n!) / ((n-p)!) //4

      //> arranjo: (n: Long, r: Long)Long
  
  def combinacao(n:Long, p:Long):
      Long = (n!) / ((p!) * ((n - p)!)) //5

      //> combinacao: (n: Long, r: Long)Long
  
  4 .!                                //> res0: Long = 24
  
  5 !                                 //> res1: Long = 120
  
  6!                                  //> res2: Long = 720
  
  (3!) + (4!)                         //> res3: Long = 30
  
  (3 + 4)!                            //> res4: Long = 5040
  
  7!                                  //> res5: Long = 5040
  
  arranjo(4,2)                        //> res6: Long = 12
  
  combinacao(4,2)                     //> res7: Long = 6

}

Nesse código temos algumas coisas que eu gostaria de ressaltar:


  1. Defino meu método factorial em uma classe Scala diferente
  2. Em um arquivo worksheet, uso a palavra chave implicit para adicionar um método à classe AnyVal, que recebe um Long como parâmetro
  3. Defino o método "!" e faço uma chamada para o método factorial, que recebe um Long
  4. Defino o método de arranjo de uma forma mais natural
  5. Defino o método de combinação de uma forma mais natural


O restante do código, mostro algumas utilizações possíveis e é pura diversão!

Teste esse código para você poder ver funcionar em sua máquina e aprenda um conceito importante nessa linguagem funcional!