1)

Abaixo está uma função python summation, que pode realizar soma de cubos / quadrados / .., operações semelhantes .

def identity(k): return k def cube(k): return pow(k, 3) def square(k): return pow(k,2) def summation(n, term): if n == 0: return 0 else: return term(n) + summation(n-1, term) def sum_cubes(n): return summation(n, cube) if __name__ == "__main__": sum = sum_cubes(4) print(sum) """ In C, We can implement the same using function pointers. Goal is, to perform similar operations(Sum of ..) using single function summation()""" 

2)

Considere, abaixo, classificar a API de C,

void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)); 

Aqui, qsort pode classificar dados de qualquer tipo , array de floats / nomes de arquivo em um diretório / strings / …


Pergunta:

Como definir uma função genérica?

summation é uma função genérica?

ou

qsort é uma função genérica?

ou

Dados dois exemplos, Função genérica uma terminologia inválida?

Nota: Termo de motivação qsort ou qualquer função de classificação que eu criar

Comentários

  • Qual definição de ” função genérica ” você leu que não ‘ não entende? Ajudaria se você postasse isso em vez de escrever um monte de código.
  • O termo da teoria de tipo para o tipo de generalismo em que uma função funciona para qualquer tipo sem restrição e sem conhecimento do tipo específico é polimorfismo paramétrico . A função de identidade é genérica desta maneira.
  • Em algumas linguagens (como Java) ” função genérica ” tem uma definição técnica específica. Mas este não é o caso em Python, então a ” função genérica ” não tem um significado bem definido. Não significa que seja ” terminologia inválida “, apenas que você deve estar ciente do contexto ao usar o termo.
  • @AndresF. Javascrpt também usa muito essa terminologia de função genérica . Porque você pode ter uma função que leva qualquer elemento html para processar (exemplo – exclua todos os filhos de um elemento html fornecido)

Resposta

Existem vários significados para” genérico “.

Definição informal

“genérico” na linguagem do dia a dia, algo que compartilha propriedades comuns, mas é menos específico em alguns aspectos.

Sob essa perspectiva, você poderia considerar qsort() como genérico: o código desta função é capaz de classificar qualquer estrutura de dados de tamanho fixo para a qual você pode definir uma função de comparação usando o algoritmo QSORT.

O mesmo se aplica à sua função summation(), que resume os termos obtidos usando qualquer função com um parâmetro.

Definição formal

Linguagens de programação como C ++ ou Java permitem a programação genérica com o uso de modelos ou genéricos:

Definição do padrão C ++ 14 : Um modelo define uma família de classes ou funções ou um alias para uma família de tipos.

O princípio é que a implementação de uma classe ou função pode ser parametrizada por tipos.

De acordo com este ponto de vista mais formal, qsort() não é uma função genérica. Sua implementação não precisa determinar nenhum tipo na compilação e seu comportamento é independente de tipo. A única coisa de que precisa é o tamanho dos elementos que estão sendo classificados e esse tamanho é um argumento comum que é processado em tempo de execução.

Para uma linguagem que não é digitada estaticamente, como Python , não tenho certeza sobre o que responder summation(). Acho que não é genérico porque sua implementação e seu comportamento não dependem do tipo: esta função é apenas uma função de ordem superior, com o argumento term sendo uma função. Não usa nenhum recurso que altere o comportamento dessa função com base nos tipos.

Para ilustração de uma função genérica, você pode dar uma olhada na função padrão C ++ std::sort() : sua implementação depende do tipo de seus argumentos (e opcionalmente uma função de comparação com argumentos de um determinado tipo). Usando os recursos dos templates C ++, ele pode classificar qualquer container de qualquer tipo, desde que tenha os operadores / funções membro / traços / iteradores que são exigidos pela implementação da função genérica.

Uma linguagem digitada dinamicamente pode ter funções genéricas

A linguagem digitada dinamicamente requer código menos genérico do que as linguagens tipadas estaticamente.

Por exemplo, se você tiver um contêiner de objetos do tipo dinâmico, uma função qsort poderia classificar genericamente o contêiner, desde que qualquer combinação de dois elementos no contêiner possa ser comparada.

Mas mesmo em um ambiente tão flexível, a programação genérica –dependente do tipo– pode ser útil. O caso de uso típico é multimétodo, em que o comportamento ou o código depende do tipo dos argumentos ou mesmo da combinação de tipos (como para determinar a interseção entre duas formas diferentes). Para obter informações adicionais, consulte:

Comentários

  • Não tenho certeza, por que estamos comparando Genéricos (principalmente usado para evitar a conversão de tipo em Java & ajuda a realizar polimorfismo) com definição de função genérica?
  • @overexchange Acho que java também oferece programação genérica, incluindo métodos genéricos (consulte a especificação ou o tutorial ). No entanto, ‘ editei um pouco a parte da definição para abordar sua observação.
  • O pacote genérico do Python não tem nada a ver com funções genéricas. Exceto que eles compartilham o mesmo adjetivo.
  • @Killian if programação genérica , é sobre a ideia de abstrair de algoritmos concretos e eficientes para obter algoritmos genéricos que podem ser combinados com diferentes representações de dados , acho que os multimétodos nesse pacote deveriam estar, não ‘ você acha?

Resposta

As funções genéricas recebem o tipo de pelo menos um argumento de função genericamente em tempo de compilação. Ou seja, o compilador descobre qual tipo é usado em um determinado local e aplica exatamente esse tipo onde é usado na função. Por exemplo. se você tiver um argumento genérico em sua função que é usado com um operador +, o tipo deve ter métodos apropriados. Para strings / arrays, isso seria em muitos casos uma concatenação e para integer / float uma adição. O compilador pode detectar se aplica a operação correta. Sua rotina C não é genérica nesse sentido, pois é o programador que aplica algumas informações de tamanho e não o compilador que detecta o tipo e usa o tamanho correto.

Por exemplo, em alguma linguagem fictícia

func add(p1,p2) { return p1+p2 } print add("a", "b") // yields "ab" print add(1, 2) // yields 3 

Aqui, o compilador detecta no primeiro caso que duas strings são aplicadas e irá expandir internamente algo como

func add(p1:string, p2:string) 

e tratar o + como concatenação, enquanto no segundo caso ele expandiria

func add(p1:int, p2:int) 

conforme fornecido Parâmetros inteiros. Genérico significa que o compilador gera código individual durante o tempo de compilação. Python, por exemplo, não é tipado e faria esse tipo de substituição durante o tempo de execução. Significa: Python não tem funções genéricas, pois tudo é meio genérico.

Comentários

  • Não entendeu. Quer dizer que + é uma função genérica, sintaxe em C ++?
  • Funções que levam argumentos de função são de ordem superior função s no mundo Python / JavaScript. Em C, precisamos de ponteiros de função, para o mesmo.
  • Veja minha edição acima.
  • Então, que tipo de função é summation, Função de ordem superior? e nada mais do que isso?
  • Existem muitas definições para o que é genérico. Stroustrup, por exemplo, define como ” programação usando tipos como parâmetros “. Para obter a referência da Wikipedia, I ‘ d prefiro ir para: en.wikipedia.org/wiki/Generic_programming

Resposta

Vou começar isso da perspectiva de C ++ e, em seguida, trabalhar meu caminho para C.

Em linguagens estaticamente tipadas como C, C ++, Java, etc., uma função “genérica” permite que você especifique as operações da função uma vez , usando marcadores para quaisquer tipos que podem variar entre chamadas diferentes (o que significa que funções como qsort e bsearch são definitivamente não funções genéricas). Idealmente, você também gostaria que o compilador detectasse automaticamente qualquer chamada para esta função genérica e gere o código real conforme necessário.

C ++ torna isso fácil 1 oferecendo modelos :

template <typename T> T summation( T *values, size_t numValues ) { T result = 0; for ( size_t i = 0; i < numValues; i++ ) result += values[i]; return result; } 

T é um espaço reservado para qualquer tipo 2 , então você pode chamá-lo como

int ivals[] = {1,2,3,4,5,6,7,8,9}; double dvals[] = {1,2,3,4,5,6,7,8,9}; int sumi = summation( ivals, 10 ); double sumd = summation( dvals, 10 ); 

Quando o código é compilado, o compilador vê as duas chamadas para summation e deduz os tipos dos argumentos. Para cada tipo diferente, ele gera uma nova instância da função, dando a ela um nome exclusivo:

int summation_i( int *values, size_t numValues ) // actual compilers will generate { // more complex "mangled" names int result = 0; // than this ... } double summation_d( double *values, size_t numValues ) { double result = 0; ... } 

Em seguida, gera o código de modo que o resultado de summation_i seja atribuído a sumi e summation_d seja atribuído a sumd.

C não oferece nada semelhante ao recurso de modelo. Tradicionalmente, atacamos a programação genérica de duas maneiras – usando macros ou usando void * em todos os lugares e delegando operações com reconhecimento de tipo para outras funções.

Aqui está um mau exemplo de uma solução baseada em macro:

#include <stdio.h> #define SUMMATION_DEF(t) \ t summation_##t( t *values, size_t numValues ) \ { \ t result = 0; \ for ( size_t i = 0; i < numValues; i++ ) \ result += values[i]; \ return result; \ } #define SUMMATION(t,x,s) summation_##t(x, s) SUMMATION_DEF(int) SUMMATION_DEF(double) int main( void ) { int ivals[] = {1, 2, 3, 4, 5}; double dvals[] = {1, 2, 3, 4, 5}; int sumi = SUMMATION(int, ivals, 5); double sumd = SUMMATION(double, dvals, 5); printf( "sumi = %d\n", sumi ); printf( "sumd = %f\n", sumd ); return 0; } 

O SUMMATION_DEF é aproximadamente semelhante a um modelo, pois especifica as operações da função, usando o parâmetro macro t como um marcador de posição de tipo. Também usamos t como parte do nome da função – o ## é o operador de colagem de token e o pré-processador expandirá t e acrescente esse valor ao nome da função 3 .

Onde ele difere do C ++ é o fato de que uma macro é apenas uma substituição de texto estúpida. Ela não aciona quaisquer operações especiais por parte do compilador. As instâncias reais da função não são geradas automaticamente com base em quaisquer invocações da macro SUMMATION – temos que gerar explicitamente as funções que queremos (daí o SUMMATION_DEF(int) e SUMMATION_DEF(double) antes de main). Também significa que, quando chamamos summation_xxx por meio da macro SUMMATION, temos que passar o tipo como parte da lista de argumentos da macro, de forma que a função correta seja chamada. Que chatice.

O O padrão C 2011 adicionou a palavra-chave _Generic, que pode tornar a vida um pouco mais fácil a esse respeito:

#include <stdio.h> #define SUMMATION_DEF(t) \ t summation_##t( t *values, size_t numValues ) \ { \ t result = 0; \ for ( size_t i = 0; i < numValues; i++ ) \ result += values[i]; \ return result; \ } #define SUMMATION(x,s) _Generic((x), \ int * : summation_int, \ double * : summation_double \ )(x, s) SUMMATION_DEF(int) SUMMATION_DEF(double) int main( void ) { int ivals[] = {1, 2, 3, 4, 5}; double dvals[] = {1, 2, 3, 4, 5}; int sumi = SUMMATION(ivals, 5); double sumd = SUMMATION(dvals, 5); printf( "sumi = %d\n", sumi ); printf( "sumd = %f\n", sumd ); return 0; } 

O _Generic palavra-chave permite que você avalie expressões com base em tipos ; portanto, se o tipo do primeiro argumento para SUMMATION é int *, chamamos summation_int; é “s it” s double *, chamamos summation_double. Dessa forma, não precisamos especificar o nome do tipo nos argumentos da macro.

A outra abordagem, como você “viu, é usar void * e delegar operações com reconhecimento de tipo a outras funções. Como eu disse acima, que” A programação não é realmente “genérica”, pois você precisa implementar manualmente cada função de comparação para cada tipo. Você não pode “codificar apenas uma vez e pronto. E usando void *, você basicamente joga a segurança de tipo pela janela e no tráfego que se aproxima.

E antes que alguém reclame – não, nenhuma dessas funções de soma verifica ou trata de estouro aritmético. Esse é um assunto para outro dia.


  1. Para definições suficientemente soltas de “fácil”. A linguagem de metaprogramação usada para dar suporte a modelos é Turing-completa, então você pode fazer coisas * realmente incríveis * e impossíveis de entender com ela.
  2. Para definições suficientemente soltas de “qualquer tipo”. Observe que qualquer tipo que você usar deve suportar o operador +=, caso contrário, o compilador gritará com você.
  3. Este código será quebrado para tipos como unsigned int ou long double, pois eles têm um espaço em branco no nome. Não sei imediatamente a solução para esse problema e gastei bastante tempo com essa resposta como ela está.

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *