Rodrigo Vidal F#, C#, CLR / Arquitetura e Desenvolvimento de Software

24abr/122

Programação Funcional – Recursão

Olá pessoal,

Hoje vamos dar início a uma discussão sobre Recursão, dentro do contexto de linguagens funcionais.

Você sabe o que é recursão? Não? A definição mais simples e respondida por desenvolvedores é a seguinte:

“Para entender recursão, você tem que entender recursão” – Anônimo

Em geral os desenvolvedores estão acostumados com as estruturas While, For, Do.. While, mas quando têm que pensar em uma solução recursiva, o raciocínio dá um nó e a solução simplesmente não sai. O problema disso é que você como desenvolvedor, acaba ficando condicionado a solucionar problemas sempre da mesma maneira. Isso não é bom certo? Existem soluções recursivas extremamente elegantes, e que podem facilitar e muito a manutenção do código e melhor expressar sua intenção. Mas para que isso possa acontecer, você deve estar familiarizado com seu funcionamento, para que rapidamente consiga entender o fluxo do algoritmo.

A estratégia de recursivamente definir uma função está em quebrar um problema em pequenas partes e então resolver esses subproblemas, quebrando-os mais ainda se for necessário

Bom vamos a alguns exemplos de funções recursivas simples para que possamos aos poucos entender seu funcionamento. É extremamente indicado que você gaste algum tempo nas implementações, e tente acompanhar o fluxo de execução, só assim o conceito se fixará. Se possível tente implementar em alguma outra linguagem. :)

O exemplo clássico: Fatorial e a Keyword “rec”

Uma função que chama ela própria é conhecida como uma função recursiva. Em F# uma função recursiva possui a keyword “rec” em sua definição. Ou seja, diferente do C# por exemplo caso, você explicitamente não informe que a função é recursiva, e tente chama-la em sua definição você receberá um erro de compilação. A razão para isso é tornar o código mais legível, e criar uma espécie de contrato para funções que desejem ser recursivas. No entanto, há algo que eu gostaria que ocorresse. Se eu defino explicitamente uma função como recursiva, caso em sua definição eu não faça a chamada para ela própria, em minha opinião também deveria ocorrer um erro de compilação. Já sinalizei isso para o Time de F#.

let rec factorial = function
    | x when x <=1 -> 1
    | x -> x * factorial (x-1)


No exemplo do Fatorial, é fácil perceber que temos duas regras explicitas na forma de Pattern Matching, repare que apenas uma delas realiza uma chamada recursiva. A razão para isso é que enquanto uma é o estabelece o caso geral, onde a função será chamada inúmeras vezes em sequencia, a outra fornece o caso base que é capaz de parar a recursão. Para o fatorial o caso base é o valor de x ser menor ou igual 1, e retornar o valor 1. Você pode notar que no calculo do fatorial o valor de x é diminuído de 1 a cada chamada a função, até que este chegue ao valor da regra base e a recursão pare.

Bom a função fatorial não é muito desafiadora, e nem apresenta um função muito prática para seu dia a dia, então vamos a exemplos um pouco mais realistas…

A Função Maximum : 'a list -> 'a when 'a : comparison

A função que chamamos aqui de maximum, está implementada por padrão em diversas linguagens como por exemplo no LINQ do C# como o método Max().

A função Maximum recebe uma lista de coisas genéricas, que podem ser colocadas em ordem, por isso implementar “comparison” que permite que dois objetos sejam comparados e retorne o maior deles. Isso pode ser expresso elegantemente usando recursão. Quer tentar?

Agora vamos ver como definimos essa função recursivamente. Primeiro, nós precisamos definir um caso base. Bom neste caso podemos dizer que o máximo de uma lista que só apresenta um elemento, é este elemento. Mas e se a lista tiver mais de um elemento? Então teremos que comparar qual é o maior, o primeiro elemento (head) da lista ou o máximo de todo o resto (tail) da lista.

let rec maximum  (list : 'a list when 'a : comparison) =
    match list with
    | [] -> failwith "bla"
    | [x] -> x
    | h::t -> max h (maximum t)


Como você pode ver utilizamos mais uma vez de pattern matching, se você não está familiarizado com o conceito dê uma olhada no post anterior aqui. Assim sendo somos capaz de estabelecer regras e descontruir valores tornando fácil expressar o problema de encontrar o valor máximo.

A primeira regra estabelece que se a função receber uma lista vazia o programa deve falhar. Isso faz sentido pois não podemos informar o maior valor de uma lista vazia. A segunda regra estabelece que se a lista só possuir um elemento, deve retornar este elemento. A terceira regra representa a fase de recursão. A lista é descontruída em Head e Tail representado pelos valores h e t respectivamente. Então nós fazemos uso da função max definida em FSharp.Core que dado dois elementos, retorna o maior elemento de dois elementos. Se h é maior que o maior elemento de t, nossa função retornará x, senão retornará o maior elemento em t.

Vamos pensar em um exemplo: Suponha que você queira saber o maior valor na lista [1;7;4].

Assim sendo a primeira regra não se aplica pois a lista não é vazia. A segunda também não pois a lista possui mais de um elemento. A terceira sim, e a lista é dividida no elemento (head) 2 e na cauda (tail) [7;4] e a função maximum é chamada novamente agora com [7;4]. Para esta nova chamada, [7;4], também cai na terceira regra, e a lista é novamente dividida no elemento 7 e na cauda [4]. A função novamente é chamada agora para [4], caindo agora na regra 2 e retornando o elemento 4 como resultado.

Agora vamos subir o nível, comparando 7 e 4 através da função max. Uma vez que 7 é maior, nós sabemos que o maior elemento de [7;4] é 7. Finalmente comparando 1 com o máximo de [7;4] que nós sabemos que é 7, nós obtemos a resposta do problema original e nosso objetivo! Uma vez que 7 também é maior que 1 nós podemos dizer que 7 é o máximo entre [1;7;4].

A Função Replicate :  int -> 'a -> 'a list

Vamos continuar exercitando os músculos recursivos do cérebro com uma nova função chamada aqui de Replicate. O objetivo da função replicate é dando um inteiro e um valor qualquer criar uma lista com esta quantidade de valor repetidos. Por exemplo, chamando replicate 3 “fsharp!” deve retornar [ “fsharp!” ; “fsharp!” ; “fsharp!” ]. Claro?!

Vamos pensar sobre as regras. A princípio podemos pensar em duas regras:

  • Se nós tentarmos replicar algo 0 vezes ou de maneira negativa, iremos receber uma lista vazia como resultado
  • Para o caso geral uma lista com n repetições de X é uma lista com X como sua cabeça (head) e uma cauda consistente de X replicado n-1 vezes.

let rec replicate n value =
    match n with
    | n when n <= 0 -> []
    | _ -> value :: (replicate (n-1) value)

Uma implementação simples e elegante.

A Função Take :  int -> 'a list -> 'a list

Mais uma? Agora vamos implementar a função Take. Esta função retorna o numero de elementos especificados de uma lista. Por exemplo a chamada take 3 [1;2;3;4;5;6] deve retornar [1;2;3]. Se nós tentarmos pegar 0 elementos de uma lista qualquer, ou n elementos de uma lista vazia obviamente receberemos uma lista vazia como resultado. Este são os dois casos base. O terceiro caso fica por conta onde obteremos os resultados mais interessante e está se encontra nossa recursão. Vamos ao algoritmo.

let rec take n list =
    match n, list with
    | (n,_) when n <=0 -> []
    | (_,[]) -> []
    | (n, h::t) -> h :: take (n-1) t

Este algoritmo é um pouco peculiar, primeiro nós fazemos uma construção e “n” e “list” em uma tupla para que passamos aplicar o pattern matching em ambos os elementos, e realizar desconstruções logo em seguida.

A Função Reverse : 'a list -> 'a list

A função reverse recebe uma lista e retorna uma lista com os mesmo elementos mas em ordem reversa. Mais uma vez uma lista vazia é o caso base, uma vez que ao reverter uma lista vazia, obtemos uma lista vazia. Quanto a regra recursiva, se dividirmos a lista original em cabeça e cauda, a lista reversa é o reverso da cauda com a cabeça acoplada ao final da lista. Veja:

let rec reverse list =
    match list with
    | [] -> []
    | h::t -> reverse t @ [h]

A Função Repeat : 'a -> seq<'a>

A função repeat recebe um elemento qualquer e retorna uma lista infinita composta daquele elemento. Com uma implementação recursiva é realmente fácil.

let rec repeat x =
     seq {
         yield x
         yield! repeat x
     }

Bom aqui temos uma construção diferente. A primeira coisa a se notar é que não usamos uma lista, e sim o que em F# é definido uma sequencia, que nada mais é que um sinônimo para IEnumerable<T>, e que permite que nossa lista seja infinita. A keyword yield funciona exatamente como o yield return do C#, e a keyword yield! (lê-se: yield bang) permite chamadas recursivas. A keyword “seq” é na verdade uma computation expression, mas isso é tema para um outro post, e é utilizada para construção de sequencias em F#.

A Função Zip : 'a list -> 'b list -> ('a * 'b) list

Zip é uma outra função para trabalhar com listas, o que ela faz é compor duas listas em uma como uma zipper mesmo. Cada elemento, da nova lista é uma tupla com os dois elementos correspondentes a mesma posição das duas listas iniciais. Exemplo zip [1;2;3] [4;5;6] resultará em [ (1,4) ; (2,5) ; (3,6) ].

let rec zip list1 list2 =
    match list1, list2 with
    | [], _ -> []
    | _, [] -> []
    | (h1::t1), (h2::t2) -> (h1, h2) :: zip t1 t2

A Função Elem : 'a -> 'a list -> bool when 'a : equality

A função elem recebe um valor e uma lista e checa se este valor está presente na lista.

let rec elem element list =
    match list with
    | [] -> false
    | h::t when element = h -> true
    | h::t -> elem element t

 

Já deu pra perceber que funções recursivas facilitam e expressam bem, uma série de funções. E você que pensou que recursão não servia para quase nada né?!

Recursão Mútua

Duas funções que chamam uma a outra são conhecidas como mutuamente recursivas e apresentam um desafio único para o sistema de inferência de tipo do F#. Para determinar o tipo da primeira função, você precisa conhecer o tipo da segunda, e vice-versa.

(*
let idOdd x = if x = 1 then true else not (isEven(x-1))
let isEven x = if x = 0 then true else not (isOdd(x-1))
*)

let rec isOdd n = (n=1) || isEven (n-1)
and     isEven n = (n = 0) || isOdd (n-1)


O exemplo acima mostra o caso de funções mutuamente recursivas, onde a função que determina se um numero é par é definido em função da função que define que uma função é impar e vice versão. O código comentado entre (**) não funciona pois o compilador irá avisa que uma das funções ainda não está definida.

Acho que eu ainda não falei sobre isso aqui no blog, mas em F# a ordem do código importa, ou seja, uma função definida abaixo da que está invocando-a irá causa um erro de compilação. Essa na verdade é uma feature da linguagem, que foi desenhada para funcionar dessa forma. A longo prazo facilita bastante a leitura e manutenção de softwares escritos.

Quicksort! QuickSort

A muito tempo atrás o @elemarjr me pediu para escrever uma versão do famoso QuickSort em F#. Para comparar acredito com a versão equivalente em Haskell, para quem não conhece o algoritmo, indico dar uma olhada na Wikipédia para não estender ainda mais este post.

let rec quicksort = function
    | [] -> []
    | h::t ->
        let smallOrEqual = t |> List.filter (fun i -> i <= h)
        let larger = t |> List.filter (fun i -> i > h)
        in quicksort smallOrEqual @ [h] @ quicksort larger

O código de referência em Haskell

quicksort :: (Ord a) => [a] -> [a]
quicksort [] = []
quicksort (x:xs) =
	let smallerOrEqual = [a | a <- xs, a <= x]
		larger = [a | a <- xs, a > x]
	in quicksort smallerOrEqual ++ [x] ++ quicksort larger

Por hoje é só pessoal!

Abraço!

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)
24abr/120

Vou palestrar no DNAD e no Qcon SP

Olá pessoal,dnad12_euvou_180x180

Este ano fui convidado para palestrar em dois eventos excelentes e que nunca tive a oportunidade palestrar.

Considero estes eventos dois dos melhores que acontecem no Brasil, quando o assunto é desenvolvimento de software.

Então se você tiver a oportunidade de participar, não a perca.

Para se inscrever:

http://dnad.dotnetarchitects.net/dnad/2012/inscricoes/qcon-logo

http://www.qcon.com.br/inscricoes

Vejo vocês lá!

Abraço,

Rodrigo Vidal

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)
15fev/122

Programação Funcional – Pattern Matching

Olá pessoal! Vamos hoje falar sobre pattern matching que é um recurso extremamente utilizado em programação funcional. Veremos alguns exemplos escritos em F#. Este post surgiu devido a uma conversa com o amigo Bernardo Rosmaninho que demonstrou interesse no assunto, e como prometido, aqui está o post :)

Segundo a Wikipédia

In computer science, pattern matching is the act of checking some sequence of tokens for the presence of the constituents of some pattern. In contrast to pattern recognition, the match usually has to be exact. The patterns generally have the form of either sequences or tree structures. Uses of pattern matching include outputting the locations (if any) of a pattern within a token sequence, to output some component of the matched pattern, and to substitute the matching pattern with some other token sequence (i.e., search and replace).

Dado isso, eu diria que pattern matching é uma série de regras que serão executadas se o padrão informado encaixar com a entrada, permitindo também sua decomposição. Esta expressão então retorna o resultado da regra acionada. Como consequência, todas as regras de um pattern match devem retornar o mesmo tipo.

Pattern matching é de alguma maneira similar ao switch do C# e do C++, mas muito mais poderoso, como veremos agora.

Você está com sorte!

let lucky = function
    | 7 -> "Você está com sorte!"
    | _ -> "Desculpe mas você está sem sorte!"


Como vemos este código está escrito em F# e define uma simples função, chamada "lucky". Está função possui duas regras, mas primeiro analizemos o tipo desta função. Executando o código acima no F# Interactive (fsi.exe) obtemos que esta função é do tipo (lucky : int -> string). Ou seja, ela recebe um valor do tipo int e retorna uma string. Note que não foi necessário definir um parâmetro para a função, e mesmo assim ela parece receber um. Este é um comportamento da keyword function utilizada, que faz com que o ultimo parâmetro seja o valor a ser comparado com a regra.

Bom então como dito anteriormente esta função possui duas regras. A primeira determina que caso o valor recebido como parâmetro do tipo inteiro seja o numero 7, então esta função retornara a string "Você está com sorte!". A segunda regra utiliza de um "underscore" para dizer que, qualquer outro valor que não satisfaça a regra anterior deve retornar "Desculpe mas você está sem sorte!". Cada regra se inicia com o pipe a esquerda. É importante notar que em F# a identação do código delimita o escopo, e o pipe deve estar identado corretamente para que seu código compile. Perceba também que, a regra é separada de seu resultado pelo operador "->".

Está função é bem simples e não apresenta nenhuma regra complexa, preparei mais algumas funções para nos familiarizarmos mais com o conceito de pattern matching. Veja se é capaz de entender o que a função abaixo faz:

let sayMe = function
    | 1 -> "One"
    | 2 -> "Two"
    | 3 -> "Three"
    | 4 -> "Four"
    | 5 -> "Five"
    | 6 -> "Six"
    | 7 -> "Seven"
    | _ -> "Not between 1 and 7"

Muito simples não é mesmo?

Pattern Matching em uma Função Recursiva

Uma implementação simples de uma função recursiva usando pattern matching é o didático fatorial. (Eu ainda não tratei de função recursivas aqui no blog, mas o post está a caminho).

Note:

let rec factorial = function
    | 0 -> 1
    | n -> n * factorial (n-1)

Em F# para determinar que uma função é recursiva é necessário utilizar a keyword "rec" explicitamente! Executando esta função no FSI, obtemos o tipo (factorial : int -> int). Ou seja recebe um inteiro e retorna um inteiro.

A primeira regra determina que se o valor do parâmetro for 0 então será retornado o valor 1, caso esta regra não se aplique, e for passado um valor diferente de zerão então o parâmetro é multiplicado por uma nova chamada a função utilizando deste valor menos um. Lindo não?

Desconstruindo Valores em Pattern Matching

Vamos supor que desejamos somar dois pontos. Segue

let addVectors v1 v2 =
    (fst v1 + fst v2, snd v1 + snd v2)

O código acima apresenta uma solução, que não utiliza de pattern matching. Pela utilização das funções fst e snd, que trabalham com tuplas com compilador do F# consegue inferir que os valores v1 e v2 são tuplas e soma os primeiros valores de cada ponto, e depois o segundo valor, e adicionalmente neste processo cria uma nova tupla como resultado.

No entanto poderíamos utilizar pattern matching em um processo de desconstrução para obtermos estes valores. Vejamos

let addVectors v1 v2 =
    match v1, v2 with
    | (x1, y1), (x2, y2) -> (x1 + x2, y1 + y2)

Nesta função utilizamos uma nova expression "match .. with" que é necessária quando a função precisa de mais de dois parâmetros.  Nesta função é necessário notar algumas coisas importantes.

  • Ela tem o tipo int * int -> int * int -> int * int , ou seja, recebe duas tuplas de inteiro e retorna uma tupla de inteiro
  • Construímos uma tupla com os valores v1 e v2 em match v1, v2 with, para utilizarmos ambos os valores na regra
  • Realizamos o processo de desconstrução da tupla na regra obtendo diretamente o valores de x1, x2, y1, y2 não sendo necessário o uso das funções.
  • Dada a desconstrução criamos uma nova tupla com os resultados somados.

O mecanismo de desconstrução torna pattern matching extremamente poderoso e permite uma melhor leitura da regra a ser aplicada, tornando seu código ainda mais legível. É também extremamente sucinta.

Pattern Matching em Funções para Tuplas

Acima nós utilizamos as funções fst e snd para obter o primeiro e o segundo valor para tuplas. No entanto vamos olhar como estas funções podem ser implementadas?

let first = function
    | (x, _, _) -> x

let second = function
    | (_, x, _) -> x

let third = function
    | (_, _, x) -> x


As três funções acima trabalham com desconstrução de tuplas de 3 elementos. Dada uma tupla de 3 elementos esta é desconstruída, e o primeiro elemento é marcado para o valor de x, feito isso a função retorna o valor de x. Feito isso podemos obter o valor de qualquer dos 3 membro de uma tupla de 3 elementos.

O operador lógico AND

Bom vamos construir uma função que funciona como o operador AND (&&)

let and x y =
    match x,y with
    | true, true -> true
    | true, false -> false
    | false, true -> false
    | false, false -> false

Devido ao mecanismo de inferência a função and recebe dois valores do tipo Booleana e retorna um novo valor.

O compilador do F# é muito poderoso como já percebemos.. Como exercício tente retirar a terceira regra e compilar o código. Você perceberá que o compilador do F# emitirá um warning avisando que uma possível regra não está sendo validada, mas irá compilar. Caso a execução caia em uma regra inexistente uma exceção do tipo MatchFailureException será lançada.

Agrupando Padrões

Vamos descrever uma função que teste se um determinado caractér é uma vogal.

let isVowel c =
    match c with
    | 'a' | 'e' | 'i' | 'o' | 'u' -> true
    | _ -> false

Perceba que neste caso estamos agrupando padrões, não havendo necessidade de criarmos uma regra para cada uma das vogais, visto que elas compartilham da mesma regra.

Guardas, Guardas!

Você já deve ter percebido como Pattern Matching é útil e permite as mais diversas construções. No entanto existem outros casos que podem ser necessários e para isso temos o que chamamos de Guards que é utilizado quando precisamos de alguma logica para saber se uma regra vai combinar.

No exemplo abaixo faremos uso de diversas construções de pattern matching. Veja:

let bmiIndex weight height =
    let bmi = weight / height ** 2.0
    let (skinny, normal, fat) = (18.5, 25.0, 30.0)
    match bmi with
    | _ when bmi <= skinny -> "You're underweight"
    | _ when bmi <= normal -> "You're normal"
    | _ when bmi <= fat -> "You're fat"
    | _ -> "You're a whale"


A função acima serve para calcular o índice de massa corpórea e informar se você está acima ou abaixo do peso. Fizemos uma função externa chamada bmiIndex que recebe os parâmetros peso e altura. Na primeira linha interna calculamos o que chamamos de bmi. Em seguida usamos pattern matching em tuplas para definir três valores. Após fazemos pattern matching no bmi e aplicamos a regra "menor ou igual". Para essa regra não ser repetida 3 vezes, eu a extraímos para a função chamada bmi, para melhorar a legibilidade. Para podemos aplicar essas regras utilizamos a keyword "when", que chamamos de when guards!

Desconstrução de Listas

Assim como fizemos com tuplas é possível descontruir listas também.

let listStatus = function
    | [] -> "the list is empty"
    | x::[] -> "The list has one element:" + string x
    | x::y::[] -> "The list has two elements " + string x + " and " + string y
    | x::y::_ -> "Too long"


A função acima dá o status de uma lista. Se ela está vazia, se possui um elemento, se possui dois elementos, ou se possuir mais elementos. Perceba que o operador :: realiza a desconstrução da lista em elementos. No caso x combina para o primeiro elemento e y para o segundo, caso possua. Caso não lembre, o operador :: é usado para construir listas como em

let list = 1::2::3::[]

Que retornaria [1;2;3].

Conclusão -> Pattern Matching Everywhere

Pattern matching como vimos é um mecanismo poderoso, e que nos permite diversas construções. Ele é simples e sucinto, o que facilita muito sua leitura. O que foi mostrado aqui não é tudo que é possível fazer com Pattern Matching. É também possível utilizar com estruturas de dados complexas criadas pelo desenvolvedor além de listas e tuplas. Em F# pattern matching é largamente utilizado até mesmo em estruturas que não parecem fazer uso desta técnica. Como no exemplo abaixo!

let xs = [(1,3), (2,4), (3,2), (6,2), (7,1)]
xs |> List.map (fun (x,y) -> x+y)

Por hoje era isso!

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)
26jan/122

JavaScript – É ou não é igual?

Olá pessoal,

Continuando a série, sobre JS, vamos falar um pouco sobre dois operadores, extremamente simples. Eles são capazes de comparar dois valores e dizer se eles são iguais ou não. Realmente simples não? Provavelmente, você sabe muito bem, como isso funciona na sua linguagem server-side, ao comparar dois valores, dois arrays, ou até mesmo dois objetos. No entanto, olhando o código que já tive a oportunidade de observar nas empresas, percebo que os desenvolvedores não entendem muito bem como isso se dá no JavaScript. Então vamos entender de uma vez por todas, se é ou não é igual.

A primeira coisa a se saber é que Javascript possui dois operadores de igualdade! O que? Dois? É isso mesmo. Você provavelmente utiliza um deles com bastante frequência: O "==". Agora você pode pensar, nossa que obvio. Isso eu já sabia. Mas você realmente sabe como este operador funciona? Você conhece seu irmão menos brincalhão? O "===" ?

Não. Eu não errei o operador acima, realmente são 3 (três) "igual" seguidos. O desconhecimento deste segundo operador é a origem de muitos bugs estarem estourando por ai, sem você realmente entender o porquê, e geralmente não tão simples de entender, principalmente, se seu código não está cobertos por testes. Espera! Testes no Javascript? (Mas isso é tema pra outro post).

Os operadores == e === checam se dois valores são iguais mas com duas definições diferentes de igualdade. Ambos os operadores aceitam operandos de qualquer tipo, e ambos retornam true se os operando forem iguais e false se eles forem diferentes. O operador === é conhecido como operador de igualdade estrita, e checa quando os dois operandos são idênticos, usando uma definição mais estrita. O operador == é conhecido como operador de igualdade, ele checa quando os dois operador são iguais usando uma definição mais relaxada que permite conversões de tipo.

Javascript suporta os operadores =, ==, ===. Podemos lê-los da seguinte forma: "é atribuído para", "é igual a", "é estritamente igual a" respectivamente.

Os operadores != e !== testam para o oposto exato dos operadores == e ===.

Objetos no Javascript são comparados por referência e não por valor. Um objeto é igual a ele mesmo, mas diferente de qualquer outro objeto. Se dois objetos distintos tem o mesmo numero de propriedades, com os mesmo nomes e mesmo valores eles ainda assim não são iguais. Dois arrays com os mesmo elementos, na mesma ordem não são iguais uns aos outros.

Como funciona o ===

O operador === avalia os operandos e então os compara, sem realizar conversão de tipo, dada a seguinte regra:

  • Se os dois valores são de tipo diferentes, eles não são iguais.
  • Se os dois valores são null ou ambos são undefined, eles são iguais.
  • Se ambos os valores são o valor booleano true ou ambos são o valor booleano false, eles são iguais
  • Se um ou mais valores são NaN, eles não são iguais. O valor NaN não é nunca igual a nenhum valor, incluindo ele mesmo.
  • Se ambos os valores são números e tem o mesmo valor, eles são iguais; Se um valor é 0 e o outro -0 eles também são iguais.
  • Se ambos os valores são strings e contém exatamente os mesmos 16 bits, nas mesmas posições, então são iguais. Se as strings diferirem em tamanho ou posicionamento, não são iguais.
  • Se ambos os valores referirem para o mesmo objeto, array, ou função, eles são iguais. Se referem para objetos diferentes não são iguais, mesmo que ambos tenham propriedades idênticas.

Como funciona o ==

O operador == é menos estrito. Se os valores dos operandos não forem do mesmo tipo, ele tenta algumas conversões de tipo e realiza a comparação novamente.

  • Se os valores tem o mesmo tipo, ele testa para igualdade estrita, como descrito acima, Se os valores forem estritamente iguais, eles são iguais.

Se os dois valores não são do mesmo tipo, eles ainda podem ser considerados iguais:

  • Se um dos valores é null e o outro é undefined, eles são iguais.
  • Se um dos valores é um numero e o outro uma string, converte a string para um numero e tenta realizar a comparação novamente, usando o valor convertido.
  • Se um é true, converte para 1 e tenta a comparação novamente, Se um é false, converte para 0 e tenta novamente.
  • Se um valor é um objeto e o outro é um numero ou string converte o objeto para um primitivo e tenta novamente a comparação. Um objeto é convertido para um valor primitivo, usando o método toString() ou valueOf().
  • Qualquer outra combinação de valores não são iguais.

Ufa! Não tão simples não é mesmo?

Segue alguns exemplos práticos que tenta permear algumas das regras acima

// Operador === 

1 === "1"
>> false

null === null
>> true

undefined === undefined
>> true

true === true
>> true

false === false
>> true

NaN === 1
>> false

NaN === NaN
>> false

2 === 2
>> true

0 === -0
>> true

"js" === " js"
>> false

"js" === "js"
>> true

var o1 = {}
>> undefined

var o2 = {}
>> undefined

o1 === o2
>> false

var r1 = [1,2,3]
var r2 = [1,2,3]
>> undefined

r1 === r2
>> false

r1 === r1
>> true

//Operador ==

null == undefined
>> true

1 == "1"
>> true

1 == true
>> true

0 == false
>> true

var o = {}
>> o == "teste"

Por hoje é só!

Abraço! :D

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)
23jan/121

JavaScript – Tipos Primitivos e Revelações

Olá pessoal, tudo bem?

Vamos falar hoje sobre sobre a linguagem mandatória para escrever aplicações web. O Javascript. E quem não tem medo do Javascript? Até hoje vejo que muitos desenvolvedores não deram e ainda não dão importância, para esta linguagem. A maioria se limita a criar funções simples com outras funções logo abaixo em um código que beira o impossível de manter. Ou então se limita ao simples uso de plugins jQuery desenvolvidos por terceiros, para colocar uma calendário mais bonitinho na aplicação. Bom, já passou da hora de você saber que javascript é extremamente importante, e você deveria domina-la tanto quanto a linguagem server-side de preferência. Eu realmente espero que você domine está ultima. :)

Não pretendo aqui contar a historia do JavaScript, ou justificar, a razão de ela possuir alguns problemas comportamentais, o importante é que você aprenda a escrever um bom código e tenha produtividade, sem esbarrar em bugs inesperados.

Bom, precisamos mudar isso, portanto, vamos ver hoje os tipos primitivos.

Qualquer valor que você use pertence a um tipo. Em javascript existem os seguintes tipos primitivos:

  1. Number  - incluir números inteiros bem como de ponto flutuante.
  2. String - qualquer numero de caracteres, por exemplo "a", "ab", "ab e c".
  3. Boolean - assume apenas dois valores, true, ou false.
  4. Undefined - quando você tenta acessar uma variável que não existe, você recebe o valor especial undefined. O mesmo acontece para uma variável que ainda não foi inicializada. O javascript na verdade a inicializa para undefined por debaixo dos panos.
  5. Null - este é outro tipo especial que somente possui um valor, o valor null. Que significa, ausência de valor, vazio, ou nada. A diferença com undefined é que se uma variável tem o valor null, ela está definida, e só acontece quando é definida para null.

Qualquer valor que não pertença a nenhum dos 5 tipos primitivos listados acima é do tipo Object.
Então basta lembrarmos que em Javascript o tipo dos dados pode ser:

  • Primitivo (os 5 listados acima)
  • Não-Primitivo (object)

O operador typeof

Se você quer saber o tipo de uma variável ou de um valor, você pode utilizar o operador typeof. Este operador retorna uma string que representa o tipo do dado. Por exemplo o operador pode retornar "number", "string", "boolean", "undefined", "object". Vejamos alguns exemplos:

Números

//Inteiro
var n = 1234;
typeof n;
>> "number"

//Ponto Flutuante
var n = 1.23;
typeof n;
>> "number"

//Octal
var n = 0377;
typeof n;
>> "number"

//Hexa
var n = 0x00;
typeof n;
>> "number"

//Exponent
var n = 1e1;
typeof n;
>> "number"


Existem um valor especial em JavaScript chamado Infinity, veja bem, é um valor especial e não um tipo. Que representa como o próprio nome diz um valor Infinito, ou um valor que o JavaScript não consegue lidar.

typeof Infinity;
>> "number"

Mas como obter este valor especial Infinity, bom, podemos.

1e309;
>> Infinity

6/0;
>> Infinity

Bom, Infinity representa uma numero extremamente grande, e como representar um numero extremamente pequeno?

-1/0
>> -Infinity

Bonito não?

Existe ainda um outro tipo especial, quando estamos lidando com números! O valor NaN! Quem nunca o viu, que atire a primeira pedra :)

A primeira coisa que eu gosto de deixar claro sobre NaN é que ele é um numero! O que? Ahn? Isso mesmo! Veja..

typeof NaN;
>> "number"

Oh my God! Provavelmente foi isso que você exclamou ao ver este exemplo! Você obtém o valor NaN quando tenta realizar uma operação que seria realizada sobre  inteiros, mas esta operação falha. Ai você obtém como retorno este tipo especial. Simples não?

Vejamos alguns exemplos:

var a = 10 * "JavaScript";
a
>> NaN

1 + 2 + 3 + 4 + NaN;
>> NaN

Perfeito!

Strings

Como vocês sabem strings são uma sequencia de caracteres. Em Javascript qualquer valor colocado entre aspas simples OU duplas é uma considerado uma string. Vejamos alguns exemplos:  

typeof "1";
>> "string" 

typeof "texto";
>> "string" 

typeof 'texto';
>> "string" 

typeof "";
>> "string"

Conversões com String

Quando você usa uma string como uma operando em uma operação aritmética (com exceção da adição, veremos o porquê), a string é convertida em um numero por debaixo dos panos.

var s = 3 * '1';
>> 3
typeof s
>> "integer"

var t = 3 + '1'
>> "31"
typeof t
>> "string"

Como podemos ver caso o operador seja adição (+) o numero 3 é convertido para string por implicitamente e o resultado é uma string "31". Para qualquer outro operador a string seria convertida em um numero como no primeiro exemplo acima.

Caso a conversão implícita falhe o resultado, como não poderia deixar de ser, será NaN.

"texto" * 3;
>> NaN


Boolean

Bom como vimos existem apenas dois valores que percentem ao tipo Boolean, true e false;

var b = true;
typeof b;
>> "boolean"

var b = false;
typeof b;
>> "boolean"


Tudo convertido para boolean é true, com exceção dos seguintes 6 valores:

  1. ""
  2. null
  3. undefined
  4. 0
  5. NaN
  6. false


Undefined

Você recebe undefined como valor quando você tenta usar uma variável que não existe ou que ainda não foi inicializada

foo
>> foo is not defined

typeof foo
>> "undefined"

var x;
typeof x;
>> "undefined"

1 + undefined;
>> NaN

1 * undefined;
>> NaN

!!undefined
>> false

"" + undefined
>> "undefined"

Null

O valor null não é atribuído pelo Javascript pode debaixo dos panos, ele somente pode ter vindo de uma inicialização do seu código

var variável = null;
>> null
typeof variável
>> "object"

var i = 1 + null;
>> 1

1*null;
>> 0

Vemos que o valor null é considerado um objeto, o que pode parecer um pouco estranho, ter um objeto que é a representação de nada. Mas veremos mais sobre em futuros posts.

Bom por hoje era isso pessoal, espero ter desmistificado um pouco sobre os tipos primitivos no Javascript.

Abraço!

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)
10jan/122

Microsoft F# MVP

Olá pessoal, Feliz Ano Novo!

Bom.. o ano começa efetivamente para mim agora, no entanto quero compartilhar com vocês uma noticia que recebi no primeiro dia deste ano. Fui nomeado Most Valuable Professional pela Microsoft na competência Visual F#.

Não é necessário dizer tamanha minha felicidade por receber esta notícia. Venho acompanhando e estudando F# bem antes desta ter sido embarcada no Visual Studio em 2010, já em sua versão 2.0 e sou apaixonado por esta linguagem.

Espero aumentar muito mais meus trabalhos aqui no blog este ano, focando em linguagens funcionais. Veremos muito mais que F# por aqui. mvp_horizontal

No mais gostaria de agradecer alguns amigos que foram essenciais na minha trajetória, para chegar até aqui. @giovannibassi, @elemarjr, @diullei, @higorcesar. Claro que muitos outros também foram importantes, mas estes quatro foram peças-chave dentro da minha trajetória como profissional. Então meu muito obrigado à vocês amigos! :)

Bom.. vamos começar?

Então F#ca na Caveira!

Abraço,
Rodrigo Vidal

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)
27dez/110

F# – Estruturas de Dados Imutáveis [Lista ; Lista ; Lista]

Fala pessoal…

Dando continuidade ao post anterior, vamos hoje falar sobre uma estrutura extremamente importante para linguagens funcionais: Listas, e o que elas apresentam de tão diferente e marcante das estruturas de lista que conhecemos.

Se você está chegando agora confira também o post anterior onde falei sobre Tuplas aqui.

O Tipo Lista

Enquanto tuplas agrupam valores em uma unica entidade, listas permitem que você ligue os dados de maneira a formar uma corrente. Uma lista pode ser vazia ou composta por um elemento e uma outra lista. Um nome especial para representar essa lista vazia pode ser “nil” e para cada elemento “cons cell” de “constructed list cell”. Na imagem abaixo vemos a representação gráfica de uma lista.

Cada cons cell contém um único valor e uma referência para o próximo elemento da lista que pode ser uma nova cons cell ou uma lista vazia.

Vamos ver alguns exemplos de construção de listas:

let listaVazia = [] 
//val listaVazia : 'a list
 
let vogais = ["a";"e";"i";"o";"u"] 
//val vogais : string list = ["a"; "e"; "i"; "o"; "u"]
 
let numeros = [1;2;3;4;5;6] 
//val numeros : int list = [1; 2; 3; 4; 5; 6]]

O código acima é bem simples e acredito que não requeira explicação. Um ponto importante a notar é o mecanismo de inferência de tipo atuando novamente. No primeiro exemplo é construida uma lista vazia, e seu tipo é uma lista genérica. No segundo exemplo é construida uma lista de strings, e no terceiro uma lista de inteiros. É importante notar que todos os elementos de uma lista devem possuir o mesmo tipo, diferentemente das tuplas que vimos anteriormente que podem agregar diferentes tipos.

Operadores de Listas

Em F# são definidos alguns operadores básicos para tratarmos com listas. As listas do F# estão definidas no modulo FSharp.List . Vamos ver algumas facilidades agora.

List Ranges

Nos permite criar listas de maneira facilitada e de maneira menos verbosa.

let range = [1..10] 
//val range : int list = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]
let charRange = ['a'..'f'] 
//val charRange : char list = ['a'; 'b'; 'c'; 'd'; 'e'; 'f']

List Comprehensions

let prepost x = [ yield x-1; yield x; yield x+1] 
let result = prepost 10 
//val prepost : int -> int list 
//val result : int list = [9; 10; 11]

No exemplo acima criamos uma função chamada “prepost” que recebe um valor “x” e a partir disso cria uma lista com três valores, o antecessor, o proprio, e seu sucessor. Perceba que utilizamos a palavara chave yield, que em F# é o equivalente como você ja deve ter imaginando do nosso querido “yield return”.

let multiplesOf3 x = [for i in 1..10 -> x * i] 
let result = multiplesOf3 5 
//val multiplesOf3 : int -> int list
//val result : int list = [5; 10; 15; 20; 25; 30; 35; 40; 45; 50]

Já neste exemplo criamos uma função que gera dez multiplos do valor passado como parametro, e utilizamos a expressão “for .. in .. –> “. É válido dizer que isso nos permite criar lógicas interessantes para construção de listas.

O Operador Cons e Append

O operador cons é represtando por “::” na verdade é uma simplificação da função List.Cons, que coloca cada novo elemento como a nova “cabeça” da lista. O operador cons é associativo a direita, o que significa que ele compõe valores da direita para a esquerda.

let numeros2 = 1 :: 2 :: 3 :: 4 :: 5 :: 6 :: [] 
//val numeros2 : int list = [1; 2; 3; 4; 5; 6]
 
let impares = [1;3;5;7;9] 
let pares = [0;2;4;6;8]
let todos = pares @ impares 
//val todos : int list = [0; 2; 4; 6; 8; 1; 3; 5; 7; 9]

O operador append, representado por “@”  é uma simplificação para a função List.append que transforma duas listas em uma.

Algumas Funções do Módulo List

Duas funções importantissimas são a função List.head que retorna a “cabeça” da lista..

let head = List.head [1..10] 
//val head : int = 1

.. e a função List.tail que retorna a cauda da lista, ou seja, todos os elementos a partir da cabeça.

let tail = List.tail [1..10] 
//val tail : int list = [2; 3; 4; 5; 6; 7; 8; 9; 10]

Estas funções são essenciais quando estamos lidando com recursão e por isso resolvi apresentá-las aqui. Ja falamos bastante sobre como trabalhar com listas com F#, no entanto, o mais interessante ainda estar por vir. Você como um leitor atento deve ter reparado que estas listas não são as mesmas listas que acompanham o .NET Framework, ou as listas, que você está acostumado a utilizar com C# no namespace System.Collections.Generic, e o tipo List<>.

Mas então o que essas listas tem de diferente?

Listas Imutáveis

Uma lista ser imutável significa que nós podemos construir uma lista, nós não podemos pegar uma lista existente e modificá-la; nós não podemos adicionar ou remover um elemento. Funções que precisam adicionar novos elementos ou removê-los sempre retornarão uma nova lista sem modificar a original, porque modificar uma lista é simplesmente impossivel. Isso está de acordo com o conceito de nós eliminarmos efeitos colaterais e indesejados em funções que manipulam listas.

Seguindo o post sobre tuplas vou mostrar como seria de maneira simples uma Lista imutável em C#

public class FuncList<t>
{
    public bool IsEmpty { get; private set; }
    public T Head { get; private set; }
    public FuncList<t> Tail { get; private set; }
 
    public FuncList()
    {
        IsEmpty = true;
    }
 
    public FuncList(T head, FuncList<t> tail)
    {
        IsEmpty = false;
        Head = head;
        Tail = tail;
    }
}
 
public static class FuncList
{
    public static FuncList<t> Empty<t>()
    {
        return new FuncList<t>();
    }
 
    public static FuncList<t> Cons<t>(T head, FuncList<t> tail)
    {
        return new FuncList<t>(head, tail);
    }
}

A classe FuncList<T> é generica, então ela pode armazenar valores de qualquer tipo. Ela possui uma propriedade IsEmpty que é True quando nós criamos uma lista vazia pelo construtor sem parâmetro. O segundo construtor recebe dois argumentos, o primeiro é a cabeça da lista e o segundo é a lista que segue como cauda para o novo valor.
Ou seja o primeiro construtor equivale a lista vazia do F# [] e o segundo ao operador Cons “::”  do F#.

Agora como criar uma lista a partir desse novo tipo? Vemos abaixo:

var numbers = FuncList.Cons(1, FuncList.Cons(2, FuncList.Cons(3, FuncList.Empty<int>())));
//Equivalente em F#
//let numbers = 1 :: 2 :: 3 :: []

Agora vamos criar um método que calcule a soma de todos os elementos de uma lista formada de inteiros

public static int SumList(FuncList<int> numbers)
{
    return numbers.IsEmpty ? 0 : numbers.Head + SumList(numbers.Tail);
}
int sum = FuncList.SumList(numbers);

A função acima faz uso de recursão todos os elementos da lista. Caso a lista esteja vazia, retorna o valor zero, caso contrário retorna a cabeça + o resultado da função novamente sobre a cauda da lista, sucessivamente até encontrar como cauda apenas a lista vazia.

Bom pessoal, por hoje era isso! Smiley de boca aberta

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)
5dez/110

F# – Estruturas de Dados Imutáveis (Tupla, Tupla)

Fala pessoal..

Hoje vamos falar sobre estruturas de dados imutáveis e o que isso quer dizer, e aproveitarei para mostrar como funcionam tuplas em F# e como seria uma implementação para Tuplas no C#.

Uma estrutura de dados imutável é uma estrutura em que o valor não muda após sua criação. Quando você declara uma estrutura que contém campos por exemplo, estes também devem ser imutáveis.

O Tipo Tupla

A estrutura mais simples em F# e o tipo Tupla. Tupla é uma estrutura simples capaz de agrupar elementos de diferentes tipos. O exemplo a seguir mostra como criar uma tupla que possui dois elementos agrupados:

let tp = (“O número é”, 42)


Como podemos ver criar uma tupla em F# é extremamente simples, nós escrevemos uma lista separada por virgulas dentro de parênteses. Mas vamos olhar com mais detalhes. O mecanismo de inferência de tipo da linguagem foi utilizado aqui, então você não precisa explicitamente dizer o tipo de sua tupla. O compilador infere que o primeiro elemento da sua tupla é uma string e o segundo é um inteiro, então podemos ler como: uma tupla que contem uma string como seu primeiro valor e um inteiro como seu segundo valor. Como podemos notar o valor de tp é do tipo string * int. Esta é a forma como é representado esta tupla, em F#.

Operações com Tuplas

Vamos começar a usar algumas operações com tuplas.

let mostrar tupla = 
	printfn "O primeiro elemento é %s e o segundo é %d" (fst tupla) (snd tupla)
 
do mostrar ("X", 7)


Neste exemplo criamos uma função chamada mostrar que recebe como parâmetro uma tupla. Nesta definição usamos a função printfn (que eu acredito que não precise de comentários) e passamos como argumento o primeiro e o segundo elemento da tupla. fst e snd são definidos como operadores em FSharp.Core.Operators e retornam o primeiro e o segundo elemento da tupla respectivamente (é uma referencia para First e Second).

Se analisarmos a função mostrar ela tem a seguinte definição (string * int –> unit). Ou seja ela recebe uma tupla de string e inteiro e retorna unit. Unit é um tipo do F# que indica que a função não retorna valor. Vemos que novamente o mecanismo de inferência de tipo entrou em cena, no entanto como pôde saber qual o tipo da tupla com que esta função sabe trabalhar? A resposta esta na string passada para a função printfn, o %s indica string e o %d indica um inteiro. A partir dai o compilador consegue inferir que estes são os tipos esperados pela função e a definição da tupla.

Tupla é uma estrutura imutável, ou seja, não podemos alterar o valor de um elemento da tupla, uma vez que a tupla tenha sido criada. Para alterarmos esse valor é necessário criar uma nova tupla. Vamos ver abaixo uma função que realiza essa operação.

let tuplaComNovoValor novoValor tupla = 
	let (original1, original2) = tupla 
	(novoValor, original2)


Definimos a função tuplaComNovoValor que cria uma nova tupla alterando o valor do primeiro item. Isso é necessário pois como dissemos anteriormente, a estrutura tupla é imutável, para modifica-la somente criando outra com seus novos valores.

Implementando um tipo Tupla em C#

Como sabemos no .NET 4 foi inserido um tipo Tuple<> genérico, que nos permite trabalhar de forma semelhante ao que fizemos com F#. No entanto meu objetivo aqui é mostrar de maneira mais simples como esse tipo foi/poderia ter sido implementado.

public sealed class Tuple<T1, T2>
{
	private readonly T1 item1;
	private readonly T2 item2;
 
	public T1 Item1
	{
		get { return item1; }
	}
 
	public T2 Item2
	{
		get { return item2; }
	}
 
	public Tuple(T1 item1, T2 item2)
	{
		this.item1 = item1;
		this.item2 = item2;
	}
 
}

O que há de mais notável neste tipo é que ele é imutável. De maneira simples, nós marcamos todos os campos com o modificador readonly e provemos apenas propriedade do tipo Get. Campos somente leitura só podem ter valores atribuídos no construtor, o que significa que uma vez criada, seu estado interno não pode ser alterado, ou mutado, assim como seus valores armazenados internamente também são imutáveis.

Implementando a mesma Tupla em F#

    type Tuple<'T1,'T2> =  
        new : 'T1 * 'T2 -> Tuple<'T1,'T2>
        member Item1 : 'T1 with get
        member Item2 : 'T2 with get


É claro que muito da implementação foi suprimida, pois não é do interesse deste post. Mas é o suficiente para expor o conceito apresentado.

Como podemos ver é muito simples trabalhar com Tuplas no F#. Em C# este trabalho se torna mais verboso, pois o mecanismo de inferência de tipo ainda não é tão poderoso.

Por hoje era isso pessoal!

Abraço!

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)
19nov/110

Encontro DNA Rio de Janeiro – 19/11/2011

Fala pessoal tudo bem?

Hoje aconteceu mais um encontro do .NETArchitects Rio de Janeiro. Foi um dia excelente e de casa cheia. Muita galera nova, e membros que não apareciam a algum tempo também voltaram. Parabéns para a comunidade carioca.

Para quem não foi, na parte da manhã tivemos uma mesa redonda sobre diversos assuntos e almoçamos no Spoleto.
Na parte da tarde o @DanielSilvaRj deu um verdadeiro Workshop sobre RavenDB, onde vimos implementação, demos uma hackeada no Raven e vimos como ele é uma solução interessante. Por fim o @JuanPLopes programou um algoritmo de ordenação topologica que pode ser encontrado aqui https://gist.github.com/1379161.

Segue uma foto da galera!

IMG_0263

Valeu a todos que compareceram, foi show!

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)
14nov/111

Programação Funcional – Expressions ao invés de Statements

Olá pessoal tudo bem?

Vou falar um pouco hoje sobre mais uma característica de programação funcional e presente na linguagem F#.

Em linguagens imperativas uma expressão é simplesmente um pedaço de código que pode ser avaliado e retorna uma resultado. Então a invocação de um método ou o uso de qualquer operador booleano ou inteiro é uma expressão. Um “statement” é uma pedaço de código que afeta o estado do programa e que não possui um resultado ou um retorno. Um chamada para um método oque não retorna nenhum valor é um statement, porque ele afeta o estado do programa.

Uma atribuição também muda o estado, alterando o valor de uma variável, mas em sua versão simples, não retorna nenhum valor, logo é um statement.

Outro exemplo típico de statement é mudar o fluxo de uma função usando a keyword “return”, ou até mesmo sair de um loop usando “break”. Ambos não possuem valor de retorno, ao invés disso, seu único proposito é mudar o estado do programa

Como você sabe, em linguagens funcionais o estado é representado pelo o que a função retorna e a única maneira de se modificar estado é retornando o valor modificado. Seguindo está logica, em linguagens funções tudo é interpretado como uma expressão com um valor de retorno. As consequências podem ser demonstradas com o seguinte exemplo

Imagine que queremos somar números de um valor a outro:

Este código muda estado de variáveis e usa quatro Statements para resolver o problema

Este código no entanto apesar de usar Recursão (que é preferível em prog. func.) não é funcional por esta escrito como uma serie de três Statements.

O que nós podemos fazer para mudar isso para uma versão mais funcional seria usar o operador ( ?: ) do C#. Com esta forma de construção nós podemos reescrever o corpo como uma única expressão que é mais próximo de como linguagens funcionais tratam todo código válido.

Como podem ver todo o corpo do método é uma expressão única que retorna um valor. Em C# isso significa que o método deveria começar com return. E nós também não poderíamos usar return e nenhum outro lugar. Em C# if-then-else é um Statement, já em F# é uma Expressão. Note que são abordagens diferentes, e linguagens funcionais utilizam Expressions em detrimento de Statements.

Por hoje era isso pessoal!

Abraço!

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)