A maneira como foi apresentada para mim, e o que eu acho que é verdade depois de ter trabalhado no aprendizado em Haskell por um mês agora, é o fato de que a programação funcional torce seu cérebro de maneiras interessantes: ela força você a pensar sobre problemas familiares de maneiras diferentes : em vez de loops, pense em mapas e dobras e filtros, etc. Em geral, se você tiver mais de uma perspectiva sobre um problema, isso o torna mais apto para raciocinar sobre o problema e alternar os pontos de vista conforme necessário.
A outra coisa realmente legal sobre Haskell é seu sistema de tipos. É estritamente tipado, mas o mecanismo de inferência de tipo faz com que pareça um programa Python que magicamente avisa quando você comete um erro estúpido relacionado ao tipo. As mensagens de erro de Haskell a esse respeito estão um pouco ausentes, mas à medida que você se familiariza mais com a linguagem, dirá a si mesmo: é isso que a digitação deve ser!
Este é o exemplo que me convenceu a aprender Haskell (e estou feliz por ter aprendido).
OK, é um programa curto e legível. Nesse sentido, é melhor do que um programa C. Mas como isso é tão diferente de (digamos) um programa Python com uma estrutura muito semelhante?
A resposta é avaliação preguiçosa. Na maioria das linguagens (mesmo algumas funcionais), um programa estruturado como o anterior resultaria no arquivo inteiro sendo carregado na memória e, em seguida, escrito novamente com um novo nome.
Haskell é "preguiçoso". Ele não calcula as coisas até que precise e, por extensão , não calcula as coisas de que nunca precisa. Por exemplo, se você remover a
writeFile
linha, Haskell não se incomodaria em ler nada do arquivo em primeiro lugar.Do jeito que está, Haskell percebe que
writeFile
depende doreadFile
e, portanto, é capaz de otimizar esse caminho de dados.Embora os resultados dependam do compilador, o que normalmente acontecerá quando você executar o programa acima é o seguinte: o programa lê um bloco (digamos, 8 KB) do primeiro arquivo, o grava no segundo arquivo e, em seguida, lê outro bloco do primeiro arquivo e grava no segundo arquivo, e assim por diante. (Tente correr
strace
nele!)... que se parece muito com o que faria uma implementação C eficiente de uma cópia de arquivo.
Portanto, Haskell permite que você escreva programas compactos e legíveis - muitas vezes sem sacrificar muito o desempenho.
Outra coisa que devo acrescentar é que Haskell simplesmente torna difícil escrever programas com erros. O incrível sistema de tipos, a falta de efeitos colaterais e, claro, a compactação do código Haskell reduzem os bugs por pelo menos três razões:
Melhor desenho do programa. A complexidade reduzida leva a menos erros lógicos.
Código compacto. Menos linhas para a existência de bugs.
Erros de compilação. Muitos bugs simplesmente não são Haskell válidos .
Haskell não é para todos. Mas todos deveriam tentar.
fonte
hSetBuffering handle (BlockBuffering (Just bufferSize))
.Data.Bytestring.Lazy.readFile
), que não têm nada a ver com o Haskell ser uma linguagem preguiçosa (não estrita). Mônadas são sequenciadas - isso significa aproximadamente "todos os efeitos colaterais acabam quando você tira o resultado". Quanto à mágica do "bytestring preguiçoso": isso é perigoso e você pode fazer isso com uma sintaxe semelhante ou mais simples na maioria das outras linguagens.readFile
também faz IO preguiçoso da mesma maneiraData.ByteString.Lazy.readFile
. Portanto, a resposta não está errada e não é apenas uma otimização do compilador. Na verdade, isso é parte da especificação de Haskell : "AreadFile
função lê um arquivo e retorna o conteúdo do arquivo como uma string. O arquivo é lido lentamente, sob demanda, como comgetContents
."const fs = require('fs'); const [file1, file2] = process.argv.slice(2); fs.createReadStream(file1).pipe(fs.createWriteStream(file2))
. O Bash também tem algo semelhante:cat $1 > $2
Você está fazendo a pergunta errada.
Haskell não é uma linguagem em que você olha alguns exemplos legais e diz "aha, entendo agora, é isso que o torna bom!"
É mais como, nós temos todas essas outras linguagens de programação, e elas são mais ou menos semelhantes, e então há Haskell que é totalmente diferente e maluco de uma forma que é totalmente incrível quando você se acostuma com a maluquice. Mas o problema é que leva um bom tempo para se aclimatar à loucura. Coisas que diferenciam Haskell de quase qualquer outra linguagem, mesmo semi-mainstream:
bem como alguns outros aspectos que são diferentes de muitas línguas convencionais (mas compartilhados por alguns):
Como alguns outros participantes responderam, a combinação de todos esses recursos significa que você pensa sobre a programação de uma maneira totalmente diferente. Portanto, é difícil encontrar um exemplo (ou conjunto de exemplos) que comunique isso adequadamente ao Joe-mainstream-programmer. É uma coisa experiencial. (Para fazer uma analogia, posso mostrar as fotos da minha viagem à China em 1970, mas depois de ver as fotos, você ainda não saberá como era ter vivido lá naquela época. Da mesma forma, posso mostrar um Haskell 'quicksort', mas você ainda não sabe o que significa ser um Haskeller.)
fonte
O que realmente diferencia Haskell é o esforço que ele faz em seu design para aplicar a programação funcional. Você pode programar em um estilo funcional em praticamente qualquer linguagem, mas é muito fácil abandoná-lo na primeira conveniência. Haskell não permite que você abandone a programação funcional, então você deve levá-lo à sua conclusão lógica, que é um programa final mais fácil de raciocinar e que contorna toda uma classe dos mais espinhosos tipos de bugs.
Quando se trata de escrever um programa para uso no mundo real, você pode achar que Haskell carece de alguma forma prática, mas sua solução final será melhor por ter conhecido Haskell para começar. Definitivamente, ainda não cheguei lá, mas até agora aprender Haskell foi muito mais esclarecedor do que, digamos, Lisp estava na faculdade.
fonte
unsafePerformIO
para pessoas que só querem ver o mundo queimar;)Parte da confusão é que a pureza e a tipagem estática permitem o paralelismo combinado com otimizações agressivas. As linguagens paralelas estão em alta agora, com o multicore sendo um pouco perturbador.
Haskell oferece mais opções de paralelismo do que qualquer linguagem de uso geral, junto com um compilador de código nativo rápido. Não há competição com este tipo de suporte para estilos paralelos:
Portanto, se você se preocupa em fazer seu multicore funcionar, Haskell tem algo a dizer. Um ótimo lugar para começar é com o tutorial de Simon Peyton Jones sobre programação paralela e concorrente em Haskell .
fonte
Memória transacional por software é uma maneira muito legal de lidar com a simultaneidade. É muito mais flexível do que a passagem de mensagens e não está sujeito a bloqueios como mutexes. A implementação do STM pelo GHC é considerada uma das melhores.
fonte
Passei o último ano aprendendo Haskell e escrevendo um projeto razoavelmente grande e complexo nele. (O projeto é um sistema de negociação de opções automatizado e tudo, desde os algoritmos de negociação até a análise e manipulação de feeds de dados de mercado de baixo nível e alta velocidade, é feito em Haskell.) É consideravelmente mais conciso e fácil de entender (para aqueles com apropriado) do que uma versão Java seria, além de extremamente robusta.
Possivelmente, a maior vitória para mim foi a capacidade de modularizar o fluxo de controle por meio de coisas como monóides, mônadas e assim por diante. Um exemplo muito simples seria o monóide de ordenação; em uma expressão como
para onde
c1
e assim por dianteLT
,EQ
ouGT
,c1
retornandoEQ
causas a expressão para continuar, avaliandoc2
; sec2
retornaLT
ouGT
esse é o valor do todo, ec3
não é avaliado. Esse tipo de coisa fica consideravelmente mais sofisticado e complexo em coisas como geradores de mensagens monádicas e analisadores, onde posso estar carregando diferentes tipos de estado, ter condições de aborto variadas ou posso querer ser capaz de decidir por qualquer chamada em particular se abortar realmente significa "nenhum processamento adicional" ou significa "retornar um erro no final, mas continuar o processamento para coletar outras mensagens de erro".Tudo isso leva algum tempo e provavelmente algum esforço para aprender e, portanto, pode ser difícil apresentar um argumento convincente para aqueles que ainda não conhecem essas técnicas. Acho que o tutorial Tudo Sobre Mônadas dá uma demonstração bastante impressionante de uma faceta disso, mas não esperaria que alguém não familiarizado com o material já "entendesse" na primeira, ou mesmo na terceira, leitura cuidadosa.
De qualquer forma, também há muitas outras coisas boas em Haskell, mas esta é uma das principais que não vejo mencionado com tanta frequência, provavelmente porque é bastante complexo.
fonte
Para obter um exemplo interessante, você pode observar: http://en.literateprograms.org/Quicksort_(Haskell)
O que é interessante é observar a implementação em várias linguagens.
O que torna o Haskell tão interessante, junto com outras linguagens funcionais, é o fato de que você tem que pensar diferente sobre como programar. Por exemplo, você geralmente não usará loops for ou while, mas usará recursão.
Como mencionado acima, Haskell e outras linguagens funcionais se destacam com processamento paralelo e aplicativos de escrita para trabalhar em vários núcleos.
fonte
Eu não poderia te dar um exemplo, sou um cara do OCaml, mas quando estou em uma situação como você, a curiosidade simplesmente toma conta e eu tenho que baixar um compilador / interpretador e tentar. Você provavelmente aprenderá muito mais dessa forma sobre os pontos fortes e fracos de uma determinada linguagem funcional.
fonte
Uma coisa que acho muito legal ao lidar com algoritmos ou problemas matemáticos é a avaliação preguiçosa inerente de Haskell de cálculos, o que só é possível devido à sua natureza estritamente funcional.
Por exemplo, se você deseja calcular todos os primos, pode usar
e o resultado é na verdade uma lista infinita. Mas Haskell irá avaliá-lo da esquerda para a direita, então contanto que você não tente fazer algo que exija a lista inteira, você ainda pode usá-la sem que o programa fique preso no infinito, como:
que soma todos os números primos menores que 100. Isso é bom por vários motivos. Em primeiro lugar, só preciso escrever uma função primo que gere todos os primos e então estou praticamente pronto para trabalhar com primos. Em uma linguagem de programação orientada a objetos, eu precisaria de alguma maneira de dizer à função quantos primos ela deveria calcular antes de retornar ou emular o comportamento de lista infinita com um objeto. Outra coisa é que, em geral, você acaba escrevendo um código que expressa o que deseja calcular e não em que ordem avaliar as coisas - em vez disso, o compilador faz isso por você.
Isso não é útil apenas para listas infinitas, na verdade, ele é usado sem que você saiba o tempo todo, quando não há necessidade de avaliar mais do que o necessário.
fonte
Concordo com outros que ver alguns pequenos exemplos não é a melhor maneira de exibir Haskell. Mas vou dar um pouco de qualquer maneira. Aqui está uma solução extremamente rápida para os problemas 18 e 67 do Projeto Euler , que pedem que você encontre o caminho de soma máxima da base ao ápice de um triângulo:
Aqui está uma implementação completa e reutilizável do algoritmo BubbleSearch de Lesh e Mitzenmacher. Usei-o para empacotar grandes arquivos de mídia para armazenamento de arquivo em DVD sem desperdício:
Tenho certeza de que este código parece um jargão aleatório. Mas se você ler a entrada do blog de Mitzenmacher e entender o algoritmo, ficará surpreso ao saber que é possível empacotar o algoritmo em código sem dizer nada sobre o que está procurando.
Tendo dado alguns exemplos conforme você pediu, direi que a melhor maneira de começar a apreciar Haskell é ler o artigo que me deu as idéias de que eu precisava para escrever o empacotador de DVD: Why Functional Programming Matters, de John Hughes. O artigo na verdade é anterior a Haskell, mas explica de maneira brilhante algumas das ideias que fazem as pessoas gostarem de Haskell.
fonte
Para mim, a atração de Haskell é a promessa de correção garantida do compilador . Mesmo que seja para partes puras do código.
Eu escrevi muitos códigos de simulação científica e me perguntei por isso muitas vezes se havia um erro em meus códigos anteriores, o que poderia invalidar um monte de trabalho atual.
fonte
Acho que para certas tarefas sou incrivelmente produtivo com Haskell.
A razão é por causa da sintaxe sucinta e da facilidade de teste.
Esta é a sintaxe da declaração da função:
Essa é a maneira mais simples que consigo pensar em definir uma função.
Se eu escrever o inverso
Posso verificar se é o inverso de qualquer entrada aleatória escrevendo
E chamando da linha de comando
O que irá verificar se todas as propriedades em meu arquivo são mantidas, testando as entradas aleatoriamente centenas de vezes.
Não acho que Haskell seja a linguagem perfeita para tudo, mas quando se trata de escrever pequenas funções e testar, não vi nada melhor. Se sua programação possui um componente matemático, isso é muito importante.
fonte
Se você conseguir entender o sistema de tipos em Haskell, acho que em si já é uma grande realização.
fonte
ele não tem construções de loop. poucas línguas têm esse traço.
fonte
Eu concordo com aqueles que disseram que a programação funcional torce seu cérebro para ver a programação de um ângulo diferente. Usei-o apenas como um hobby, mas acho que mudou fundamentalmente a maneira como abordo um problema. Não acho que teria sido tão eficaz com LINQ sem ter sido exposto a Haskell (e usando geradores e compreensões de lista em Python).
fonte
Para apresentar uma visão contrária: Steve Yegge escreve que as linguagens Hindely-Milner carecem da flexibilidade necessária para escrever bons sistemas :
Vale a pena aprender Haskell, mas tem suas próprias fraquezas.
fonte