O que há de tão ruim no Template Haskell?

252

Parece que a Template Haskell é frequentemente vista pela comunidade Haskell como uma conveniência lamentável. É difícil colocar em palavras exatamente o que observei a esse respeito, mas considere estes poucos exemplos

Eu já vi várias postagens no blog em que as pessoas fazem coisas bem legais com o Template Haskell, permitindo uma sintaxe mais bonita que simplesmente não seria possível no Haskell comum, bem como uma tremenda redução de clichê. Então, por que o modelo Haskell é menosprezado dessa maneira? O que o torna indesejável? Em que circunstâncias o Template Haskell deve ser evitado e por quê?

Dan Burton
fonte
56
Eu discordo do voto para mudar; Estou fazendo esta pergunta com o mesmo espírito que perguntei O que há de tão ruim na E / S preguiçosa? e espero ver respostas da mesma maneira. Estou aberto a reformular a pergunta se isso ajudaria.
Dan Burton
51
@ErikPhilips Por que você não deixa as pessoas que freqüentam essa tag decidirem se ela pertence aqui? Parece que sua única interação com a comunidade Haskell é fazer suas perguntas.
Gabriel Gonzalez
5
@GabrielGonzalez é óbvio com a pergunta atual e responda que ela não segue as perguntas frequentes sobre que tipo de pergunta eu não devo perguntar aqui: não há nenhum problema real a ser resolvido . A questão não tem um problema específico de código resolvido e é apenas conceitual por natureza. E com base na pergunta que devo evitar o haskell do modelo, ele também cai no Stack Overflow não é um mecanismo de recomendação .
Erik Philips
27
@ErikPhilips O aspecto do Mecanismo de recomendação é irrelevante para esta pergunta, porque você notará que isso se refere a uma decisão entre diferentes ferramentas (por exemplo, "diga-me qual idioma devo usar"). Por outro lado, estou apenas pedindo explicações sobre o Template Haskell especificamente, e o FAQ declara "se sua motivação é" eu gostaria que outros me explicassem [em branco] para mim "), então você provavelmente está bem". Compare com, por exemplo, o GOTO ainda considerado prejudicial?
Dan Burton
29
Votação para reabrir. Só porque é uma pergunta de nível superior, não significa que não seja boa.
György Andrasek

Respostas:

171

Uma razão para evitar Template Haskell é que, como um todo, não é totalmente seguro para o tipo, contrariando muito o "espírito de Haskell". Aqui estão alguns exemplos disso:

  • Você não tem controle sobre que tipo de Haskell AST um pedaço de código TH irá gerar, além de onde ele aparecerá; você pode ter um valor do tipo Exp, mas não sabe se é uma expressão que representa a [Char]ou a (a -> (forall b . b -> c))ou o que for. O TH seria mais confiável se alguém pudesse expressar que uma função pode gerar apenas expressões de um determinado tipo, ou apenas declarações de função, ou apenas padrões de correspondência de construtor de dados, etc.
  • Você pode gerar expressões que não são compiladas. Você gerou uma expressão que referencia uma variável livre fooque não existe? Com sorte, você verá apenas isso quando realmente usar seu gerador de código, e somente nas circunstâncias que acionam a geração desse código específico. Também é muito difícil realizar testes unitários.

O TH também é totalmente perigoso:

  • O código executado em tempo de compilação pode ser arbitrário IO, incluindo o lançamento de mísseis ou o roubo do seu cartão de crédito. Você não precisa procurar em todos os pacotes cabal que baixar em busca de explorações de TH.
  • O TH pode acessar funções e definições "privadas do módulo", quebrando completamente o encapsulamento em alguns casos.

Existem alguns problemas que tornam as funções TH menos divertidas de usar como desenvolvedor de bibliotecas:

  • O código TH nem sempre é passível de composição. Digamos que alguém produza um gerador para lentes e, na maioria das vezes, esse gerador será estruturado de tal maneira que só poderá ser chamado diretamente pelo "usuário final" e não por outro código TH, por exemplo, uma lista de construtores de tipo para os quais gerar lentes como parâmetro. É complicado gerar essa lista no código, enquanto o usuário precisa apenas escrever generateLenses [''Foo, ''Bar].
  • Os desenvolvedores nem sabem que o código TH pode ser composto. Você sabia que sabe escrever forM_ [''Foo, ''Bar] generateLens? Qé apenas uma mônada, para que você possa usar todas as funções usuais. Algumas pessoas não sabem disso e, por causa disso, criam várias versões sobrecarregadas de essencialmente as mesmas funções com a mesma funcionalidade, e essas funções levam a um certo efeito de inchaço. Além disso, muitas pessoas escrevem seus geradores na Qmônada, mesmo quando não precisam, o que é como escrever bla :: IO Int; bla = return 3; você está dando a uma função mais "ambiente" do que precisa, e os clientes da função são obrigados a fornecer esse ambiente como efeito disso.

Finalmente, existem algumas coisas que tornam as funções TH menos divertidas de usar como usuário final:

  • Opacidade. Quando uma função TH tem um tipo Q Dec, ela pode gerar absolutamente qualquer coisa no nível superior de um módulo e você não tem absolutamente nenhum controle sobre o que será gerado.
  • Monolitismo. Você não pode controlar o quanto uma função TH gera, a menos que o desenvolvedor permita; se você encontrar uma função que gera uma interface de banco de dados e uma interface de serialização JSON, não pode dizer "Não, eu só quero a interface do banco de dados, obrigado; rolarei minha própria interface JSON"
  • Tempo de execução. O código TH leva um tempo relativamente longo para ser executado. O código é interpretado novamente toda vez que um arquivo é compilado e, muitas vezes, uma tonelada de pacotes é requerida pelo código TH em execução, que precisa ser carregado. Isso diminui consideravelmente o tempo de compilação.
dflemstr
fonte
4
Adicione a isso o fato de que o template-haskell tem sido historicamente muito pouco documentado. (Embora eu tenha olhado novamente e pareça que as coisas estão pelo menos um pouco melhores agora.) Além disso, para entender o template-haskell, você precisa entender a gramática da linguagem Haskell, que impõe uma certa complexidade (não é um esquema). Essas duas coisas contribuíram para eu intencionalmente não me incomodar em entender TH quando eu era iniciante em Haskell.
precisa saber é o seguinte
14
Não se esqueça que o uso do Template Haskell de repente significa que a ordem das declarações é importante! O TH simplesmente não está integrado tão firmemente quanto se poderia esperar, dado o polimento suave de Haskell (seja 1.4, 98, 2010 ou mesmo Glasgow).
Thomas M. DuBuisson
13
Você pode argumentar sobre o Haskell sem muita dificuldade, não há essa garantia sobre o Template Haskell.
augustss
15
E o que aconteceu com a promessa de Oleg de uma alternativa segura para o TH? Refiro-me ao seu trabalho baseado em seu artigo "Finalmente sem etiqueta, parcialmente avaliado" e mais de suas anotações aqui . Parecia tão promissor quando o anunciaram e nunca mais ouvi uma palavra sobre isso.
Gabriel Gonzalez
53

Esta é apenas a minha opinião.

  • É feio de usar. $(fooBar ''Asdf)simplesmente não parece bom. Superficial, claro, mas contribui.

  • É ainda mais feio escrever. Às vezes, a citação funciona, mas na maioria das vezes você precisa fazer enxertos e encanamentos manuais em AST. A API é grande e pesada, há sempre muitos casos com os quais você não se importa, mas ainda precisa despachar, e os casos com os quais você se preocupa tendem a estar presentes em várias formas semelhantes, mas não idênticas (dados versus novo tipo, registro estilo vs. construtores normais, e assim por diante). É chato e repetitivo escrever e complicado o suficiente para não ser mecânico. A proposta de reforma aborda parte disso (tornando as cotações mais amplamente aplicáveis).

  • A restrição de palco é um inferno. Não conseguir dividir as funções definidas no mesmo módulo é a parte menor: a outra conseqüência é que, se você tiver uma emenda de nível superior, tudo o que estiver depois no módulo ficará fora do escopo para qualquer coisa anterior. Outras linguagens com essa propriedade (C, C ++) a tornam viável, permitindo que você encaminhe declarações, mas Haskell não. Se você precisar de referências cíclicas entre declarações emendadas ou suas dependências e dependentes, geralmente está ferrado.

  • É indisciplinado. O que quero dizer com isso é que, na maioria das vezes, quando você expressa uma abstração, existe algum tipo de princípio ou conceito por trás dessa abstração. Para muitas abstrações, o princípio por trás delas pode ser expresso em seus tipos. Para classes de tipo, você pode frequentemente formular leis que as instâncias devem obedecer e os clientes podem assumir. Se você usar o novo recurso genérico do GHC para abstrair a forma de uma declaração de instância sobre qualquer tipo de dados (dentro dos limites), você poderá dizer "para tipos de soma, funciona assim, para tipos de produtos, funciona assim". O modelo Haskell, por outro lado, são apenas macros. Não é abstração no nível das idéias, mas abstração no nível das ASTs, o que é melhor, mas apenas modestamente, do que a abstração no nível do texto sem formatação. *

  • Liga você ao GHC. Em teoria, outro compilador poderia implementá-lo, mas na prática duvido que isso aconteça. (Isso contrasta com várias extensões de sistema de tipo que, embora possam apenas ser implementadas pelo GHC no momento, eu poderia facilmente imaginar ser adotado por outros compiladores no futuro e eventualmente padronizado.)

  • A API não é estável. Quando novos recursos de idioma são adicionados ao GHC e o pacote template-haskell é atualizado para suportá-los, isso geralmente envolve alterações incompatíveis com os versões anteriores dos tipos de dados TH. Se você deseja que seu código TH seja compatível com mais de uma versão do GHC, você precisa ter muito cuidado e usar CPP.

  • Há um princípio geral de que você deve usar a ferramenta certa para o trabalho e a menor que seja suficiente, e nessa analogia, o modelo Haskell é algo assim . Se existe uma maneira de fazer isso que não é o Template Haskell, geralmente é preferível.

A vantagem do Template Haskell é que você pode fazer coisas que não poderia fazer de outra maneira, e isso é importante. Na maioria das vezes, as coisas para as quais o TH é usado só poderiam ser feitas se elas fossem implementadas diretamente como recursos do compilador. O TH é extremamente benéfico para ter ambos, porque permite fazer essas coisas e porque você protótipo de extensões em potencial do compilador de uma maneira muito mais leve e reutilizável (veja os vários pacotes de lentes, por exemplo).

Para resumir por que acho que existem sentimentos negativos em relação ao Template Haskell: ele resolve muitos problemas, mas para qualquer problema resolvido, parece que deve haver uma solução melhor, mais elegante e disciplinada, mais adequada para resolver esse problema, um que não resolva o problema gerando automaticamente o padrão, mas removendo a necessidade de ter o padrão.

* Embora eu ache frequentemente que CPPtem uma melhor relação potência / peso para os problemas que ele pode resolver.

EDIT 23-04-14: O que eu frequentemente tentava abordar acima, e apenas recentemente obtive exatamente, é que há uma distinção importante entre abstração e desduplicação. A abstração adequada geralmente resulta em desduplicação como efeito colateral, e a duplicação geralmente é um sinal revelador de abstração inadequada, mas não é por isso que é valiosa. Abstração adequada é o que torna o código correto, compreensível e sustentável. A desduplicação apenas a torna mais curta. O modelo Haskell, como macros em geral, é uma ferramenta para desduplicação.

glaebhoerl
fonte
"O CPP tem uma melhor relação potência / peso para os problemas que ele pode resolver". De fato. E no C99 ele pode resolver o que você quiser. Considere o seguinte: COS , Caos . Também não entendo por que as pessoas pensam que a geração AST é melhor. É apenas mais ambigüidade e menos ortogonal a outros recursos de linguagem
Britton Kerin
31

Gostaria de abordar alguns dos pontos mencionados pelo dflemstr.

Não acho que você não possa verificar TH como algo preocupante. Por quê? Porque mesmo se houver um erro, ainda haverá tempo de compilação. Não tenho certeza se isso reforça meu argumento, mas isso é semelhante em espírito aos erros que você recebe ao usar modelos em C ++. Eu acho que esses erros são mais compreensíveis que os erros do C ++, pois você obterá uma versão impressa do código gerado.

Se uma expressão TH / quase-quoter faz algo tão avançado que cantos difíceis podem se esconder, então talvez seja desaconselhável?

Eu quebro essa regra bastante com quasi-quoters em que tenho trabalhado ultimamente (usando haskell-src-exts / meta) - https://github.com/mgsloan/quasi-extras/tree/master/examples . Eu sei que isso introduz alguns erros, como não poder emendar as compreensões de lista generalizadas. No entanto, acho que há uma boa chance de que algumas das idéias em http://hackage.haskell.org/trac/ghc/blog/Template%20Haskell%20Proposal acabem no compilador. Até então, as bibliotecas para analisar Haskell em árvores TH são uma aproximação quase perfeita.

Em relação à velocidade / dependência da compilação, podemos usar o pacote "zeroth" para alinhar o código gerado. Isso é pelo menos agradável para os usuários de uma determinada biblioteca, mas não podemos fazer muito melhor no caso de editar a biblioteca. As dependências de TH podem inchar os binários gerados? Eu pensei que deixou de fora tudo o que não é referenciado pelo código compilado.

A restrição de preparação / divisão das etapas de compilação do módulo Haskell é péssima.

Opacidade do RE: é o mesmo para qualquer função de biblioteca que você chamar. Você não tem controle sobre o que Data.List.groupBy fará. Você apenas tem uma "garantia" / convenção razoável de que os números de versão informam sobre a compatibilidade. É uma questão de mudança diferente quando.

É aqui que o uso do zeroth compensa - você já está fazendo a versão dos arquivos gerados - para saber sempre quando a forma do código gerado foi alterada. Observar as diferenças pode ser um pouco complicado, porém, para grandes quantidades de código gerado, então esse é um lugar onde uma melhor interface de desenvolvedor seria útil.

Monolitismo do ER: Você certamente pode pós-processar os resultados de uma expressão TH, usando seu próprio código em tempo de compilação. Não seria muito código filtrar o tipo / nome da declaração de nível superior. Você pode imaginar escrever uma função que faça isso genericamente. Para modificar / desmonolitizar os quasiquoters, é possível padronizar a correspondência no "QuasiQuoter" e extrair as transformações usadas, ou fazer uma nova em termos dos antigos.

mgsloan
fonte
1
Em relação à opacidade / monolitismo: é claro que você pode percorrer [Dec]e remover coisas que não deseja, mas digamos que a função lê um arquivo de definição externa ao gerar a interface JSON. Só porque você não usa isso Decnão faz o gerador parar de procurar o arquivo de definição, fazendo com que a compilação falhe. Por esse motivo, seria bom ter uma versão mais restritiva da Qmônada que permitisse gerar novos nomes (e coisas assim), mas não permitisse IO, de modo que, como você diz, alguém pudesse filtrar seus resultados / fazer outras composições .
precisa saber é o seguinte
1
Eu concordo, deve haver uma versão não IO de Q / cotação! Isso também ajudaria a resolver - stackoverflow.com/questions/7107308/… . Depois de garantir que o código em tempo de compilação não faça nada inseguro, parece que você pode simplesmente executar o verificador de segurança no código resultante e garantir que ele não faça referência a coisas particulares.
mgsloan
1
Você já escreveu seu contra-argumento? Ainda aguardando o seu link prometido. Para aqueles que procuram o conteúdo antigo de esta resposta: stackoverflow.com/revisions/10859441/1 , e para aqueles que podem ver o conteúdo excluído: stackoverflow.com/revisions/10913718/6
Dan Burton
1
existe uma versão mais atualizada do zeroth do que a do hackage? Esse (e o repositório darcs) foram atualizados pela última vez em 2009. Ambas as cópias não são compiladas com um ghc atual (7.6).
aavogt
1
@aavogt tgeeky estava trabalhando para consertá-lo, mas acho que ele não terminou: github.com/technogeeky/zeroth Se ninguém fizer isso / criar algo para isso, vou resolver isso eventualmente.
mgsloan
16

Esta resposta é uma resposta às questões levantadas por illissius, ponto por ponto:

  • É feio de usar. $ (fooBar '' Asdf) simplesmente não parece bom. Superficial, claro, mas contribui.

Concordo. Sinto que $ () foi escolhido para parecer que fazia parte do idioma - usando o familiar palete de símbolos de Haskell. No entanto, é exatamente isso que você não quer nos símbolos usados ​​para a emenda de macro. Definitivamente se misturam demais, e esse aspecto cosmético é bastante importante. Gosto da aparência de emendas, porque elas são visualmente distintas.

  • É ainda mais feio escrever. As citações funcionam algumas vezes, mas na maioria das vezes você precisa fazer enxertos e encanamentos manuais em AST. A [API] [1] é grande e pesada, há sempre muitos casos com os quais você não se importa, mas ainda precisa despachar, e os casos com os quais você se importa tendem a estar presentes em várias formas semelhantes, mas não idênticas (dados x newtype, estilo de registro x construtores normais e assim por diante). É chato e repetitivo escrever e complicado o suficiente para não ser mecânico. A [proposta de reforma] [2] aborda parte disso (tornando as cotações mais amplamente aplicáveis).

Também concordo com isso, no entanto, como observam alguns dos comentários em "Novas direções para o TH", a falta de boas citações AST prontas para uso não é uma falha crítica. Neste pacote WIP, busco solucionar esses problemas no formato de biblioteca: https://github.com/mgsloan/quasi-extras . Até agora, permito a emenda em mais alguns lugares do que o habitual e posso combinar os padrões nos ASTs.

  • A restrição de palco é um inferno. Não conseguir dividir as funções definidas no mesmo módulo é a parte menor: a outra conseqüência é que, se você tiver uma emenda de nível superior, tudo o que estiver depois no módulo ficará fora do escopo para qualquer coisa anterior. Outras linguagens com essa propriedade (C, C ++) a tornam viável, permitindo que você encaminhe declarações, mas Haskell não. Se você precisar de referências cíclicas entre declarações emendadas ou suas dependências e dependentes, geralmente está ferrado.

Já me deparei com a questão das definições cíclicas de TH antes ... É bastante irritante. Existe uma solução, mas é feia - envolva as coisas envolvidas na dependência cíclica em uma expressão TH que combina todas as declarações geradas. Um desses geradores de declarações poderia ser apenas um quasi-quoter que aceita o código Haskell.

  • É sem princípios. O que quero dizer com isso é que, na maioria das vezes, quando você expressa uma abstração, existe algum tipo de princípio ou conceito por trás dessa abstração. Para muitas abstrações, o princípio por trás delas pode ser expresso em seus tipos. Quando você define uma classe de tipo, geralmente pode formular leis que as instâncias devem obedecer e os clientes podem assumir. Se você usar o [novo recurso genérico] do GHC [3] para abstrair a forma de uma declaração de instância sobre qualquer tipo de dados (dentro dos limites), poderá dizer "para tipos de soma, funciona assim, para tipos de produtos, funciona assim" " Mas o Template Haskell é apenas macros burras. Não é abstração no nível das idéias, mas abstração no nível das ASTs, o que é melhor, mas apenas modestamente, do que abstração no nível do texto sem formatação.

Só é sem princípios se você fizer coisas sem princípios. A única diferença é que, com o compilador implementado mecanismos para abstração, você tem mais confiança de que a abstração não está vazando. Talvez democratizar o design da linguagem pareça um pouco assustador! Os criadores de bibliotecas de TH precisam documentar bem e definir claramente o significado e os resultados das ferramentas que eles fornecem. Um bom exemplo de TH com princípios é o pacote derivado: http://hackage.haskell.org/package/derive - ele usa uma DSL de forma que o exemplo de muitas das derivações / especifique / a derivação real.

  • Liga você ao GHC. Em teoria, outro compilador poderia implementá-lo, mas na prática duvido que isso aconteça. (Isso contrasta com várias extensões de sistema de tipo que, embora possam apenas ser implementadas pelo GHC no momento, eu poderia facilmente imaginar ser adotado por outros compiladores no futuro e eventualmente padronizado.)

Esse é um ponto muito bom - a API do TH é bastante grande e desajeitada. Reimplementar, parece que pode ser difícil. No entanto, existem realmente apenas algumas maneiras de reduzir o problema de representar ASTs da Haskell. Eu imagino que copiar os TH ADTs e gravar um conversor na representação AST interna o levaria a uma boa parte do caminho até lá. Isso seria equivalente ao esforço (não insignificante) de criar haskell-src-meta. Também poderia ser simplesmente reimplementado imprimindo bastante o TH AST e usando o analisador interno do compilador.

Embora eu possa estar errado, não vejo o TH como uma extensão de compilador tão complicada, do ponto de vista da implementação. Este é realmente um dos benefícios de "manter as coisas simples" e não ter a camada fundamental como um sistema de modelos teoricamente atraente e estaticamente verificável.

  • A API não é estável. Quando novos recursos de idioma são adicionados ao GHC e o pacote template-haskell é atualizado para suportá-los, isso geralmente envolve alterações incompatíveis com os versões anteriores dos tipos de dados TH. Se você deseja que seu código TH seja compatível com mais de uma versão do GHC, você precisa ter muito cuidado e usar CPP.

Este também é um bom argumento, mas um pouco dramático. Embora tenha havido adições à API recentemente, elas não foram extensivamente indutoras de quebras. Além disso, acho que, com a citação AST superior que mencionei anteriormente, a API que realmente precisa ser usada pode ser substancialmente reduzida. Se nenhuma construção / correspondência precisar de funções distintas e, em vez disso, for expressa como literais, a maior parte da API desaparecerá. Além disso, o código que você escreve seria portado mais facilmente para representações AST para idiomas semelhantes ao Haskell.


Em resumo, acho que o TH é uma ferramenta poderosa e semi-negligenciada. Menos ódio pode levar a um ecossistema de bibliotecas mais animado, incentivando a implementação de mais protótipos de recursos de linguagem. Tem sido observado que o TH é uma ferramenta sobrecarregada, que pode deixar você / fazer / quase qualquer coisa. Anarquia! Bem, é minha opinião que esse poder pode permitir que você supere a maioria de suas limitações e construa sistemas capazes de abordagens de meta-programação bastante baseadas em princípios. Vale a pena o uso de hacks feios para simular a implementação "adequada", pois dessa forma o design da implementação "adequada" ficará gradualmente claro.

Na minha versão ideal pessoal do nirvana, grande parte da linguagem sairia do compilador, para bibliotecas dessa variedade. O fato de os recursos serem implementados como bibliotecas não influencia fortemente sua capacidade de abstrair fielmente.

Qual é a resposta típica de Haskell ao código padrão? Abstração. Quais são as nossas abstrações favoritas? Funções e tipeclasses!

As classes de tipos permitem definir um conjunto de métodos que podem ser usados ​​em todos os tipos de funções genéricas nessa classe. Entretanto, além disso, a única maneira de as classes ajudarem a evitar clichês é oferecendo "definições padrão". Agora, aqui está um exemplo de um recurso sem princípios!

  • Conjuntos mínimos de ligação não podem ser declarados / verificados pelo compilador. Isso pode levar a definições inadvertidas que resultam em fundo devido à recursão mútua.

  • Apesar da grande conveniência e poder que isso renderia, você não pode especificar padrões de superclasse, devido a instâncias órfãs http://lukepalmer.wordpress.com/2009/01/25/a-world-without-orphans/ Isso permitiria corrigir o hierarquia numérica graciosamente!

  • A busca por recursos do tipo TH para padrões de métodos levou a http://www.haskell.org/haskellwiki/GHC.Generics . Embora isso seja interessante, minha única experiência em depurar códigos usando esses genéricos era quase impossível, devido ao tamanho do tipo induzido e ao ADT tão complicado quanto um AST. https://github.com/mgsloan/th-extra/commit/d7784d95d396eb3abdb409a24360beb03731c88c

    Em outras palavras, isso ocorreu após os recursos fornecidos pelo TH, mas foi necessário elevar um domínio inteiro da linguagem, a linguagem da construção, para uma representação do sistema de tipos. Embora eu possa vê-lo funcionando bem para o seu problema comum, para os complexos, parece propenso a produzir uma pilha de símbolos muito mais aterrorizante do que os hackers da TH.

    O TH fornece a computação em tempo de compilação em nível de valor do código de saída, enquanto os genéricos obriga a elevar a parte de correspondência / recursão de padrão do código no sistema de tipos. Embora isso restrinja o usuário de algumas maneiras bastante úteis, não acho que a complexidade valha a pena.

Penso que a rejeição do TH e da metaprogramação do tipo lisp levaram à preferência por coisas como padrões de método, em vez de declarações de instâncias mais flexíveis e macroexpansíveis. A disciplina de evitar coisas que podem levar a resultados imprevisíveis é sábia, no entanto, não devemos ignorar que o sistema de tipos capazes de Haskell permite uma metaprogramação mais confiável do que em muitos outros ambientes (verificando o código gerado).

mgsloan
fonte
4
Essa resposta não se sustenta muito bem: você está fazendo várias referências a outra resposta que eu tenho que procurar antes de poder ler a sua corretamente.
precisa
É verdade. Tentei deixar claro o que estava sendo falado, apesar disso. Talvez eu edite para alinhar os pontos de illisuis.
mgsloan
Devo dizer que talvez "sem princípios" seja uma palavra mais forte do que eu deveria ter usado, com algumas conotações que não pretendia - certamente não é inescrupuloso! Esse ponto de bala foi o que eu mais tive problemas, porque tenho esse sentimento ou idéia não formada em minha cabeça e dificuldade em colocá-lo em palavras, e "sem princípios" foi uma das palavras que compreendi que estava em algum lugar nas proximidades. "Disciplinado" é provavelmente mais próximo. Não tendo uma formulação clara e sucinta, fui para alguns exemplos. Se alguém puder me explicar mais claramente o que eu provavelmente quis dizer, eu agradeceria!
glaebhoerl
(Também acho que você pode ter mudado-se a restrição de teste e citações feias-a-escrita.)
glaebhoerl
1
Doh! Obrigado por apontar isso! Fixo. Sim, indisciplinado provavelmente seria a melhor maneira de colocá-lo. Penso que a distinção aqui é realmente entre mecanismos de abstração "embutidos" e, portanto, "bem entendidos", versus "ad-hoc" ou mecanismos de abstração definidos pelo usuário. Suponho que eu quero dizer é que você pode conseguir definir uma biblioteca TH que implementou algo bastante semelhante ao envio typeclass (ainda que em tempo de compilação não runtime)
mgsloan
8

Um problema bastante pragmático com o Template Haskell é que ele só funciona quando o interpretador de bytecode do GHC está disponível, o que não é o caso em todas as arquiteturas. Portanto, se o seu programa usa o Template Haskell ou depende de bibliotecas que o utilizam, ele não será executado em máquinas com uma CPU ARM, MIPS, S390 ou PowerPC.

Isso é relevante na prática: o git-anexo é uma ferramenta escrita em Haskell que faz sentido executar em máquinas preocupadas com armazenamento, essas máquinas geralmente têm CPUs não i386. Pessoalmente, eu corro o git-anexo em um NSLU 2 (32 MB de RAM, CPU de 266 MHz; você sabia que o Haskell funciona bem nesse hardware?) Se ele usasse o Template Haskell, isso não é possível.

(A situação sobre o GHC no ARM está melhorando bastante atualmente e acho que 7.4.2 funciona mesmo, mas o ponto ainda permanece).

Joachim Breitner
fonte
1
"O modelo Haskell conta com o compilador e intérprete de bytecode do GHC para executar as expressões de emenda". - haskell.org/ghc/docs/7.6.2/html/users_guide/…
Joachim Breitner
2
ah, eu que - não, o TH não funcionará sem o interpretador de bytecode, mas isso é diferente de (embora relevante para) o ghci. Eu não ficaria surpreso se houvesse uma relação perfeita entre a disponibilidade de ghci e a disponibilidade do interpretador de bytecode, já que o ghci depende do interpretador de bytecode, mas o problema é a falta do interpretador de bytecode, não a falta de ghci especificamente.
muhmuhten 18/07/2013
1
(aliás, ghci tem divertidamente fraco suporte para uso interativo de TH tentar. ghci -XTemplateHaskell <<< '$(do Language.Haskell.TH.runIO $ (System.Random.randomIO :: IO Int) >>= print; [| 1 |] )')
muhmuhten
Ok, com o ghci eu estava me referindo à capacidade do GHC de interpretar (em vez de compilar) o código, independentemente de o código vir interativamente no binário do ghci ou da emenda do TH.
Joachim Breitner
6

Por que o TH é ruim? Para mim, tudo se resume a isso:

Se você precisa produzir tanto código repetitivo que se encontra tentando usar o TH para gerá-lo automaticamente, está fazendo errado!

Pense nisso. Metade do apelo de Haskell é que seu design de alto nível permite evitar grandes quantidades de código inútil que você precisa escrever em outros idiomas. Se você precisa de geração de código em tempo de compilação, está basicamente dizendo que o seu idioma ou o design do seu aplicativo falhou. E nós programadores não gostamos de falhar.

Às vezes, é claro, é necessário. Mas, às vezes, você pode evitar a necessidade de TH apenas sendo um pouco mais inteligente com seus projetos.

(A outra coisa é que o TH é de nível bastante baixo. Não há um design de alto nível; muitos detalhes de implementação interna do GHC estão expostos. E isso torna a API propensa a mudanças ...)

MathematicsOrchid
fonte
Acho que isso não significa que seu idioma ou aplicativo falhou com você, especialmente se considerarmos o QuasiQuotes. Sempre há trocas quando se trata de sintaxe. Algumas sintaxas descrevem melhor um determinado domínio; portanto, você deseja mudar para outra sintaxe algumas vezes. O QuasiQuotes permite alternar elegantemente entre sintaxes. Isso é muito poderoso e é usado pelo Yesod e outros aplicativos. Ser capaz de escrever código de geração HTML usando sintaxe que parece HTML é um recurso incrível.
CoolCodeBro
@CoolCodeBro Sim, quase-citar é muito bom, e suponho que seja um pouco ortogonal ao TH. (Obviamente, ele é implementado em cima do TH.) Eu estava pensando mais em usar o TH para gerar instâncias de classe ou criar funções de várias aridades, ou algo assim.
MathematicalOrchid