Muito mais empolgante do que aprender uma nova linguagem de programação é aprender um novo
paradigma de programação.
A parte mais louca é perceber como o paradigma funciona. Isso acontece de modo intuitivo, muito parecido com como quando se aprende uma língua nova: nada faz sentido no começo, tudo é muito mecânico; de repente um estalo e tudo faz sentido!
Há muitos paradigmas de programação,
já andei falando disso antes, mas muitos são variações dos mesmos tipos básicos: paradigmas imperativo, funcional e declarativo.
Programação imperativa
É o primeiro paradigma com o qual a maioria dos programadores trava contato.
Na programação imperativa, o programa se parece com uma receita de bolo: uma sequência de ordens, chamadas comandos ou instruções (
statements em inglês), que devem ser executadas.
A partir desse conceito, derivam diversos paradigmas secundários. O principal é a programação estruturada ou procedimental (
procedural em inglês), onde os comandos são organizados em grupos, chamados funções, que podem ser evocados em momentos diferentes.
As funções podem receber ou não parâmetros, que alteram seu comportamento, e podem retornar valores. Em algumas linguagens, quando o grupo de comandos não recebe parâmetros nem retorna valores, ele é chamado subrotina.
Para exemplificar o funcionamento da programação imperativa, vamos implementar
fatorial em
C – mais simples impossível.
Para quem não sabe, fatorial consiste em uma função recursiva cuja parada é:
0! = 1
E o passo é:
n! = n * (n - 1)!
Outra forma de entender é reiterativamente:
n! = 1 * 1 * 2 * 3 * … * (n - 2) * (n - 1) * n
Vamos implementar a função reiterativa em C para ilustrar melhor o paradigma:
#include <stdlib.h>
#include <stdio.h>
int factorial(int);
int main(int argc, char **argv) {
printf("O fatorial de 5 é %d\n", factorial(5));
return EXIT_SUCCESS;
}
int factorial(int x) {
int result = 1;
int i;
for (i=1; i<=x; ++i)
result *= i;
return result;
}
Cada comando é uma ordem dada ao sistema: atribua 1 à variável
result
; para cada
i
de 1 até o valor do argumento
x
, multiplique o valor de
result
pelo valor de
i
; retorne o valor de
result
.
São ordens dadas ao sistema.
[update 2011-07-24]
Na programação imperativa, é muito comum a manipulação de alterações de estado, daí o uso de variáveis – contentores (ou slots) que podem sofrer alterações de valor ao longo da existência do processo em execução.
[/update]
Orientação a objetos
Orientação a objetos não passa de um variante da programação imperativa, mas um variante digno de citação.
Na orientação a objetos, as ordens não são dadas a um sistema abstrato, mas objetos recebem as ordens e as executam.
O conceito de objeto é bem genérico: qualquer coisa pode ser um objeto, um número, uma janela na tela, uma coleção…
Na orientação a objetos as ordens dadas a um objeto são chamadas mensagens e a definição de como o objeto reage a cada mensagem é chamada método.
O exemplo será a versão recursiva de fatorial implementada em
Smalltalk:
!Integer methodsFor: 'mathematical functions'!
factorial
self = 0 ifTrue: [↑ 1].
self > 0 ifTrue: [↑ self * (self - 1) factorial].
self error: 'Not valid for negative integers'.
!
!!
Transcript
show: 'O fatorial de 5 é ';
show: 5 factorial printString;
cr.
[update 2011-07-16]
Atualizei o código em Smalltalk segundo implementação da máquina virtual Pharo.
[/update]
O princípio é parecido com o anterior, mas em vez de dar uma ordem ao sistema – calcule o fatorial de 5 –, é dada ao próprio número – número 5, qual seu fatorial?
Observação: a orientação a objetos pode ser aplicada também à programação funcional.
Programação funcional
Enquanto na programação imperativa ordens são dadas ao sistema ou a objetos, no paradigma funcional são definidas funções, como as matemáticas, e o programa nasce da interação entre as funções: o resultado de umas funções é passado como parâmetro para outras.
[update 2011-07-24]
Na programação funcional, o estado do sistema tende a ser constante, havendo apenas a troca de informação por parâmetros. Assim é comum que não haja variáveis, mas incógnitas constantes, que não sofrem (ou não devem sofrer) alteração de valor ao longo da execução do programa.
[/update]
O mesmo exemplo, fatorial, em
Common Lisp:
(defun factorial ((x integer))
(if (zerop x)
1
(* x (factorial (- x 1)))))
(format t "~%O fatorial de 5 é ~A~&" (factorial 5))
O conceito é ligeiramente difente: a função
factorial
, que recebe um parâmetro inteiro nomeado
x
, é definida como o resultado da função
if
; a função
if
recebe como primeiro parâmetro o resultado da função
zerop
, que é verdadeiro quando
x
é igual a zero; o segundo parâmetro de
if
, 1, é o resultado caso o primeiro parâmetro seja verdadeiro; o terceiro parâmetro é o resultado caso seja falso; o terceiro parâmetro é o resultado da função de multiplicação. Entendendo até aqui, o resto é autoexplicativo.
[update 2011-06-19]
Bônus!
Fatorial em Scheme:
(define (factorial x)
(if (zero? x)
1
(* x (factorial (- x 1)))))
(display "O fatorial de 5 é ")
(display (factorial 5))
(newline)
E em Erlang:
-module (fact).
-export([factorial/1]).
factorial(0) -> 1;
factorial(X) -> X * factorial(X - 1).
Salve como fact.erl
. No prompt:
1> c("fact.erl").
{ok,fact}
2> fact:factorial(5).
120
[/update]
Programação declarativa
Este paradigma é um dos mais complicados para
pescar…
[update 2011-07-24]
Na programação declaração o código diz o que o programa deve fazer, não como.
[/update]
O programa consiste em uma lista de declarações de verdades.
Nos paradigmas anteriores havia variáveis, que sofriam atribuições. Na programação declarativa há incógnitas, que não sofrem atribuições! O valor de cada incógnita é constante e inicialmente desconhecido. O que o programa faz é cruzar as consultas (
queries) com as declarações que formam o conjunto verdade para deduzir o valor das incógnitas.
O exemplo consiste no fatorial implementado em
Prolog:
factorial(0, 1).
factorial(N, F) :-
N > 0,
N1 is N - 1,
factorial(N1, F1),
F is N * F1.
O que este conjunto verdade diz é que o fatorial de 0 é 1 e que o fatorial de
N
é
F
quando:
N
é maior que zero; N1
é N
menos 1; - o fatorial de
N1
é F1
; - e
F
é igual a N
vezes F1
.
Para a consulta:
| ?- [factorial].
fatorial.pro compiled, 7 lines read - 869 bytes written, 7 ms
(1 ms) yes
| ?- factorial(5, X),
write('O fatorial de 5 é '),
write(X),
nl.
Para entender como funciona, há um
applet em Java em um
tutorial que demonstra o chinês. É só encontrar o
applet na página, ir clicando em
Step e ver acontecer.
A linguagem declarativa da vez é Erlang.[update 2011-06-19]
Na época deste artigo, em vez de estudar Erlang, perguntei por aí e fui informado que Erlang seria uma linguagem declarativa. Agora que tomei vergonha na cara e estudei um pouco, descobri que é uma linguagem funcional, extremamente similar a Haskell.
Para experimentar Erlang, há o applet Try Erlang.
[/update]
[]’s
Cacilhας, La Batalema