Jump to content

First class functions/strategy pattern - Afixem na vossa linguagem preferida


pedrotuga

Recommended Posts

Vá... Objective-C/Foundation:

int (^soma)(int, int) = ^(int a, int b) { return a+b; };
int (^multiplica)(int, int) = ^(int a, int b) { return a*b; };
int calcula(int a, int b, int (^block)(int, int)) { return block(a, b); }

calcula(1, 2, soma);
calcula(1, 2, multiplica);

Alternativamente é possível utilizar selectors, mas as chamadas são significativamente diferentes.

“There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies. The first method is far more difficult.”

-- Tony Hoare

Link to comment
Share on other sites

Aqui vai em C

#include <stdio.h>

int calcular(int a, int b, int (*fx)(int, int)) { return fx(a, b); }

int soma(int a, int b) { return a + b; }
int multiplicacao(int a, int  { return a * b; }

int main(void) {
    int v[2];
    v[0] = calcular(1, 2, soma); /* devolve 3 */
    v[1] = calcular(1, 2, multiplicacao); /* devolve 2 */
    printf("1 + 2 = %d\n", v[0]);
    printf("1 * 2 = %d\n", v[1]);
    return 0;
}

What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Link to comment
Share on other sites

C#

public static int soma(int a, int b) { return (a + b); }
public static int multiplica(int a, int b) { return (a * b); }
public static int calcula(int a, int b, Func<int, int, int> operacao) { return operacao(a,b); }

public static void Main(string[] args)
{
   Console.WriteLine(calcula(2, 5, soma));
   Console.WriteLine(calcula(2, 5, multiplica));
}
Link to comment
Share on other sites

Python:

def soma(a, b):
   return a+b;

def multiplica(a, b):
   return a*b;

def calcula(a, b, op):
   return op(a, b);

calcula(1, 2, soma);
calcula(1, 2, multiplica);

“There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies. The first method is far more difficult.”

-- Tony Hoare

Link to comment
Share on other sites

Acho que esta é uma demonstração melhor... Porque é suposto que as funções não possam apenas ser recebidas, como também retornadas.

A grande vantagem é podermos alterar comportamentos... E podemos fazer isto de diversas formas...

use 5.010; #só para poder utilizar o say

my %operacoes = (
    "soma" => sub { return  $_[0] + $_[1]; };
    "multiplica" => sub { return $_[0] * $_[1] };
);


sub novo_calculo = {
    my ($oper, $esquerdo, $direito) = @_;

    if(exists $operacoes{$oper}) {
        return sub { return $operacoes{$oper}->($esquerdo, $direito); };
    }
    else {
        die "Operação: '$operacao', não suportada";
    }
}


my $soma = novo_calculo("soma", 1, 2);
say &$soma();

my $multiplicador = novo_calculo("multiplicacao", 1 , 2);
say &$multiplicador();

Agora imaginem que queremos adicionar suporte para divisão, mas queremos impedir divisões por zero:


use 5.010; #só para poder utilizar o say

my %operacoes = (
    "soma" => sub { return  $_[0] + $_[1]; },
    "multiplica" => sub { return $_[0] * $_[1] },
    "divide" => sub { return $_[0] / $_[1] },
);


my %seguranca = (
    "divide" => sub {
        die "Não se pode dividir por zero (0), nem por valor indefinido" unless($_[1]);
    },
);


sub novo_calculo = {
    my ($oper, $esquerdo, $direito) = @_;

    if(exists $operacoes{$oper}) {
        $seguranca{$oper}->($esquerdo, $direito) if(exists $seguranca{$oper});

        return sub { return $operacoes{$oper}->($esquerdo, $direito); };
    }
    else {
        die "Operação: '$operacao', não suportada";
    }
}

my $divisao = novo_calculo("divide", 1,2);
say &$divisao();
Link to comment
Share on other sites

Em Pascal, usando a Directive Compiler que define que a notação utilizada é a do Delphi:

{$mode delphi}
PROGRAM referencia;
TYPE TFuncao = function(v1, v2 : integer) : integer;

FUNCTION soma(v1, v2 : integer) : integer;
begin
    soma := v1 + v2;
end;

FUNCTION multiplica(v1, v2 : integer) : integer;
begin
    multiplica := v1 * v2;
end;

PROCEDURE Calcula(a, b : integer; f : TFuncao);
begin
    writeln(f(a,b));
end;

BEGIN
    Calcula(1, 2, soma);
    Calcula(1, 2, multiplica);
    readln;
END.

Há muitos anos atrás, seria assim em ANSI Pascal, onde estava directamente no parâmetro a referência à função:

PROGRAM referencia;

FUNCTION soma(v1, v2 : integer) : integer;
begin
    Result := v1 + v2;
end;

FUNCTION multiplica(v1, v2 : integer) : integer;
begin
    Result := v1 * v2;
end;

PROCEDURE Calcula(a, b : integer; function(v1,v2:integer):integer);
begin
    writeln(f(a,b));
end;

BEGIN
    Calcula(1, 2, soma);
    Calcula(1, 2, multiplica);
    readln;
END.

Knowledge is free!

Link to comment
Share on other sites

Como me admirei de o PHP ainda não estar aqui, vasculhei na web para ver como se fazia e aqui está:

<?php
$soma = function($a, $b) {
 return $a + $b;
};

$multiplicacao = function($a, $b) {
 return $a * $b;
};

$calcular = function($a, $b, $op) {
 return $op($a, $b);
};

echo $calcular(1,2,$soma); //devolve 3
echo $calcular(1,2,$multiplicacao); //devolve 2
?>

http://stackoverflow.com/a/1005890/515814

http://www.codediesel.com/php/anonymous-functions-in-php/

Nick antigo: softclean | Tens um projeto? | Wiki P@P

Ajuda a comunidade! Se encontrares algo de errado, usa a opção "Denunciar" por baixo de cada post.

Link to comment
Share on other sites

Em Forth

: multiplicacao ( a b -- a * b ) * ;
: soma ( a b -- a + b ) + ;
: calcular ( a b op -- a op b ) execute ;

1 2 ' multiplicacao calcular .
1 2 ' soma calcular .

As primeiras linhas são definições; as linhas assinaladas são expressões (o operador . imprime o valor do topo do stack).

What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Link to comment
Share on other sites

Java:

interface Operacao {
   public int calc(int a, int b);
}

class Soma implements Operacao {
   public int calc(int a, int b) { return a+b; }
}

class Multiplica implements Operacao {
   public int calc(int a, int b) { return a*b; }
}

public int calcula(int a, int b, Operacao op) {
   return op.calc(a, b);
}

calcula(1, 2, new Soma());
calcula(1, 2, new Multiplica());

Com uns singletons a coisa era capaz de ficar melhor.

“There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies. The first method is far more difficult.”

-- Tony Hoare

Link to comment
Share on other sites

Lisp (Common Lisp) ... parecido com Forth

[1]> (defun soma (a b) (+ a b))
SOMA
[2]> (defun multiplicacao (a b) (* a b))
MULTIPLICACAO
[3]> (defun calcular (a b op) (funcall op a b))
CALCULAR
[4]> (calcular 1 2 (function soma))
3
[5]> (calcular 1 2 (function multiplicacao))
2

Atenção: eu não sei Lisp. O exemplo acima pode ser muito mau exemplo (mas funciona).

What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Link to comment
Share on other sites

Lisp (Common Lisp) ... parecido com Forth

[1]> (defun soma (a b) (+ a b))
SOMA
[2]> (defun multiplicacao (a b) (* a b))
MULTIPLICACAO
[3]> (defun calcular (a b op) (funcall op a b))
CALCULAR
[4]> (calcular 1 2 (function soma))
3
[5]> (calcular 1 2 (function multiplicacao))
2

Atenção: eu não sei Lisp. O exemplo acima pode ser muito mau exemplo (mas funciona).

Normalmente em vez de se escrever (function foo) escreve-se #'foo.

Por isso o exemplo seria:

CL-USER> (defun soma (a b) (+ a b))
SOMA
CL-USER> (defun multiplicacao (a b) (* a b))
MULTIPLICACAO
CL-USER> (defun calcular (a b op) (funcall op a b))
CALCULAR
CL-USER> (calcular 1 2 #'soma)
3
CL-USER> (calcular 1 2 #'multiplicacao)
2

Se for em Scheme, o código não precisa do "funcall" e do #'

1 ]=> (define (soma a b) (+ a b))

;Value: soma

1 ]=> (define (multiplicacao a b) (* a b))

;Value: multiplicacao

1 ]=> (define (calcular a b op) (op a b))

;Value: calcular

1 ]=> (calcular 1 2 soma)

;Value: 3

1 ]=> (calcular 1 2 multiplicacao)

;Value: 2

Em clojure:

user=> (defn soma [a b] (+ a b))
#'user/soma
user=> (defn multiplicacao [a b] (* a b))
#'user/multiplicacao
user=> (defn calcular [a b op] (op a b))
#'user/calcular
user=> (calcular 1 2 soma)
3
user=> (calcular 1 2 multiplicacao)
2

Não me responsabilizo por qualquer dano ocorrido no seguimento dos meus conselhos. Prontos, a minha pessoa está oficialmente protegida legalmente 😄

Link to comment
Share on other sites

Normalmente em vez de se escrever (function foo) escreve-se #'foo.

Obrigado.

Mas, mas ... o Lisp tem influencias do Perl? LOL

(Sim, eu sei: quando muito o Perl tem influencias do Lisp)

What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Link to comment
Share on other sites

Eu gosto particularmente do snippet em java e é talvez o que tenha usado mais na minha vida por ter sido a linguagem que usei mais.

Apesar de não ser propriamente uma linguagem orientada para paradigma funcional, há uma maneira (pelo menos) de se implementar este padrão.

O exemplo de em C 'prova' mais ou menos a mesma teoria.

Pessoalmente acredito que a escolha da linguagem é um tópico sobrevalorizado. Claro que as linguagens têm características diferentes, mas mais importante é o artesão que as usa. Espero que este tópico esteja a contribuir para passar esssa ideia.

Boas contribuções pessoal. Algum corajoso que comece a aventurar-se por linguagens mais esotéricas? Brainfuck, whitespace, ML, fortran...?

Link to comment
Share on other sites

Ja que ninguem meteu em C++, apesar de nao ser nada de novo, aqui vai:

int soma(int a,int b){return a+b;}
int multiplicacao(int a, int b){return a*b;}

//C++11 implementacao dos functions
int calcFunction(int a,int b, std::function<int (int, int)> func){return func(a,b);}


//igual ao do pmg
int calc(int a,int b,int (*fx)(int, int)){return fx(a,b);}

//utilizar overload do operador()
struct OverLoadFunc
{
   int operator()(int a,int b,int (*func)(int, int)){return func(a,b);}
};

//Igual ao do KTachyon so' que em C++
class Operacao
{
public:
   virtual int calc(int a,int b)=0;
};

class Soma:public Operacao
{
   int calc(int a,int b){return a+b;}
};
class Multiplicacao:public Operacao
{
   int calc(int a,int b){return a*b;}
};

int calcula(int a,int b,Operacao *op)
{
   return op->calc(a,b);
}

   //std::functions
   cout<<calcFunction(4,3,soma)<<endl;
   cout<<calcFunction(4,3,multiplicacao)<<endl;

   //como a do pmg
   cout<<calc(4,3,soma)<<endl;
   cout<<calc(4,3,multiplicacao)<<endl;

//overload do operator()
OverLoadFunc conta;
cout<<conta(4,3,soma)<<endl;
cout<<conta(4,3,multiplicacao)<<endl;

   //como a do KTachyon
   cout<<calcula(4,3,new Soma)<<endl;
   cout<<calcula(4,3,new Multiplicacao)<<endl;

Por muito mais que que estude só aprendo uma coisa, que ainda tenho muita coisa para aprender.

A beleza de um código está em decompor problemas complexos em pequenos blocos simples.

"learn how to do it manually first, then use the wizzy tool to save time."

"Kill the baby, don't be afraid of starting all over again. Fail soon, learn fast."

Link to comment
Share on other sites

Não a minha linguagem favorita, mas vai:

soma(a, b) { return a+b; }
multiplicacao(a, b) { return a*b; }
calcular(a,b,operacao) { return operacao(a,b);}

main() {
  print(calcular(1,2,soma)); //devolve 3
  print(calcular(1,2,multiplicacao)); //devolve 2
}

Quem adivinha esta linguagem? (não está listada no code tag ) Dica: web, Google

Link to comment
Share on other sites

Boas contribuções pessoal. Algum corajoso que comece a aventurar-se por linguagens mais esotéricas? Brainfuck, whitespace, ML, fortran...?

É impossível fazer em brainfuck e whitespace (nem sequer tem funções, quanto mais serem de primeira ordem).

Em ML... Pode ser OCaml? Isto, apesar do rumbafum ter feito em F#, que é quase a mesma coisa:

let soma a b = a + b
let multiplicacao a b = a * b
let calcular a b operacao = operacao a b

Modo de usar:

calcular 3 2 soma;; (* sai 5 *)
calcular 3 2 multiplicacao;; (* sai 6 *)

Quem adivinha esta linguagem? (não está listada no code tag ) Dica: web, Google

Dart?

"Para desenhar um website, não tenho que saber distinguir server-side de client-side" - um membro do fórum que se auto-intitula webdesigner. Temo pelo futuro da web.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.