Showing posts with label métodos implicitos. Show all posts
Showing posts with label métodos implicitos. Show all posts

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!