Pergunta

Vindo de C ++, acho programação genérica indispensável. Eu me pergunto como as pessoas se aproximam de que em Haskell?

dizer como fazer função swap genérico escrita em Haskell?

Existe um conceito equivalente a especialização parcial em Haskell?

C ++, que pode parcialmente especializar-se a função de comutação genérico com um especial para um contentor MAP / hash_map genérico que tem um método de permuta especial para o (1) troca de recipiente. Como você fazer isso em Haskell ou o que é o exemplo canônico de programação genérica em Haskell?

Foi útil?

Solução

Isto está intimamente relacionada com a sua outra pergunta sobre Haskell e quicksort. Eu acho que você provavelmente precisa ler pelo menos o introdução de um livro sobre Haskell. Soa como se você ainda não compreendeu o ponto-chave sobre o assunto que é que ele proíbe-o de modificar os valores das variáveis ??existentes.

Troca (como compreendido e utilizado em C ++) é, por sua própria natureza, todos sobre como modificar os valores existentes. É assim que nós podemos usar um nome para se referir a um recipiente, e substituir esse recipiente com completamente diferentes conteúdos, e especializar-se que a operação para ser rápido (e sem exceção) para recipientes específicos, o que nos permite implementar uma abordagem Modificar-e-publicar (crucial para escrever código de exceção-safe ou a tentativa de escrever código livre-lock).

Você pode escrever uma troca genérica em Haskell, mas provavelmente levaria um par de valores e retornar um novo par contendo os mesmos valores com as suas posições invertidas, ou algo parecido. Não é realmente a mesma coisa, e não ter as mesmas utilizações. Não faria qualquer sentido tentar e especializar-lo para um mapa por cavar dentro daquele mapa e trocar suas variáveis ??de membro individuais, porque você simplesmente não está autorizado a fazer coisas como que em Haskell (que você pode fazer a especialização, mas não a modificação de variáveis).

Suponha que queria "medida" uma lista em Haskell:

measure :: [a] -> Integer

Isso é uma declaração de tipo. Isso significa que a função measure leva uma lista de tudo (a é um parâmetro de tipo genérico porque ele começa com uma letra minúscula) e retorna um inteiro. Então, isso funciona para uma lista de qualquer tipo de elemento - é o que seria chamado de modelo de função em C ++, ou uma função polimórfica em Haskell (não o mesmo que uma classe polimórfica em C ++)

.

Agora podemos definir que, fornecendo especializações para cada caso interessante:

measure [] = 0

i. medir a lista vazia e você recebe zero.

Aqui está uma definição muito geral que abrange todos os outros casos:

measure (h:r) = 1 + measure r

O bit entre parênteses na LHS é um padrão. Isso significa: ter uma lista, quebre a cabeça e chamá-lo h, chamar a parte r restante. Esses nomes são, então, os parâmetros que podemos usar. Isso irá corresponder a qualquer lista com pelo menos um item sobre ele.

Se você já tentou modelo metaprogramming em C ++ tudo isso vai ser velho chapéu para você, porque envolve exatamente o mesmo estilo - recursão para fazer loops, especialização para fazer a recursão terminar. Só que em Haskell ele funciona em tempo de execução (especialização da função de valores ou padrões de valores particulares).

Outras dicas

Como Earwicker sais, o exemplo não é tão significativa em Haskell. Se você absolutamente querer tê-lo de qualquer maneira, aqui é algo semelhante (trocando as duas partes de um par), c & p a partir de uma sessão interativa:

GHCi, version 6.8.2: http://www.haskell.org/ghc/  :? for help
Loading package base ... linking ... done.
Prelude> let swap (a,b) = (b,a)
Prelude> swap("hello", "world")
("world","hello")
Prelude> swap(1,2)
(2,1)
Prelude> swap("hello",2)
(2,"hello")

Em Haskell, as funções são tão genérico (polimórfica) possível - o compilador inferir o "tipo mais geral". Por exemplo, o exemplo de swap de TheMarko é polimórfica por padrão na ausência de uma assinatura de tipo:

* Principal> deixe swap (a, b) = (b, a)
* Principal>: t troca
troca :: (t, t1) -> (t1, t)

Como para especialização parcial, GHC tem uma extensão não-98:
file: /// C : /ghc/ghc-6.10.1/doc/users_guide/pragmas.html#specialize-pragma

Além disso, nota que há uma incompatibilidade na terminologia. O que é chamado genérico em C ++, Java e C # é chamado polimórfica em Haskell. "Genérico" em Haskell geralmente significa politípica: http://haskell.readscheme.org/generic.html
Mas, aboe eu uso o c ++ significado do genérico.

Em Haskell você criaria classes tipo. classes de tipo não são como aulas de linguagens OO. Leve a turma tipo numérico Ele diz que qualquer coisa que é uma instância da classe pode executar determinadas operações (+ - * /) para Integer é um membro da Numérico e fornece implementações das funções necessárias para ser considerado numérico e pode ser usado em qualquer lugar um numérico é esperado.

Digamos que você queira ser capaz de foo Ints e Cordas. Então você teria que declarar Int e String para ser instâncias da classe Foo tipo. Agora qualquer lugar que você veja o tipo (Foo a) agora você pode usar Int ou cadeia.

A razão pela qual você não pode adicionar ints e flutua diretamente é porque add tem o tipo (a Numérico) a -> a -> aa é uma variável do tipo e, assim como variáveis ??regulares ela só pode ser ligado uma vez de forma breve como você ligá-la para Int cada um na lista deve ser Int.

Depois de ler o suficiente em um livro Haskell para realmente compreender a resposta de Earwicker eu sugiro que você leia também sobre as classes de tipo. Eu não tenho certeza o que “especialização parcial” significa, mas parece que eles poderiam chegar perto.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top