Continuo ouvindo esse termo em vários contextos diferentes. O que é isso?
Continuo ouvindo esse termo em vários contextos diferentes. O que é isso?
Respostas:
A programação declarativa é quando você escreve seu código de forma que ele descreva o que você deseja fazer, e não como você deseja fazê-lo. Cabe ao compilador descobrir o como.
Exemplos de linguagens de programação declarativas são SQL e Prolog.
As outras respostas já fazem um trabalho fantástico explicando o que é programação declarativa, então apenas fornecerei alguns exemplos de por que isso pode ser útil.
Os programas declarativos são independentes do contexto . Como eles apenas declaram qual é o objetivo final, mas não as etapas intermediárias para atingir esse objetivo, o mesmo programa pode ser usado em contextos diferentes. Isso é difícil de fazer com programas imperativos , porque eles geralmente dependem do contexto (por exemplo, estado oculto).
Tome yacc
como exemplo. É um gerador de analisador aka. compilador, um DSL declarativo externo para descrever a gramática de um idioma, para que um analisador para esse idioma possa ser gerado automaticamente a partir da descrição. Devido à sua independência de contexto, você pode fazer muitas coisas diferentes com essa gramática:
yacc
)E muitos mais …
Como você não prescreve o computador que etapas a seguir e em que ordem, ele pode reorganizar seu programa com muito mais liberdade, talvez até executar algumas tarefas em paralelo. Um bom exemplo é um planejador de consultas e um otimizador de consultas para um banco de dados SQL. A maioria dos bancos de dados SQL permite exibir a consulta que eles estão realmente executando versus a consulta que você pediu para executar. Muitas vezes, essas consultas não parecem nadaGostam um do outro. O planejador de consultas leva em consideração coisas que você nem imaginaria: latência rotacional do prato de disco, por exemplo, ou o fato de que algum aplicativo completamente diferente para um usuário completamente diferente executasse uma consulta semelhante e a tabela que você está participar e que você trabalhou tanto para evitar o carregamento já está na memória de qualquer maneira.
Há um trade-off interessante aqui: a máquina tem de trabalhar mais para descobrir como fazer algo do que seria em uma linguagem imperativa, mas quando se faz descobrir isso, ele tem muito mais liberdade e muito mais informação para a optimização palco.
Vagamente:
A programação declarativa tende a:
A programação imperativa tende a:
Como resultado, um estilo imprescindível ajuda o leitor a entender a mecânica do que o sistema está realmente fazendo, mas pode fornecer poucas informações sobre o problema que ele pretende solucionar. Por outro lado, um estilo declarativo ajuda o leitor a entender o domínio do problema e a abordagem que o sistema adota para a solução do problema, mas é menos informativo sobre a questão da mecânica.
Programas reais (mesmo aqueles escritos em idiomas que favorecem os fins do espectro, como ProLog ou C) tendem a ter os dois estilos presentes em vários graus e em vários pontos, para satisfazer as diversas complexidades e necessidades de comunicação da peça. Um estilo não é superior ao outro; eles apenas servem a propósitos diferentes e, como em muitas coisas na vida, a moderação é fundamental.
Aqui está um exemplo.
Em CSS (usado para estilizar páginas HTML), se você deseja que um elemento de imagem tenha 100 pixels de altura e 100 pixels de largura, basta "declarar" que é isso que você deseja da seguinte maneira:
#myImageId {
height: 100px;
width: 100px;
}
Você pode considerar o CSS uma linguagem declarativa de "folha de estilo".
O mecanismo do navegador que lê e interpreta esse CSS é gratuito para fazer com que a imagem pareça tão alta e larga como quiser. Diferentes mecanismos do navegador (por exemplo, o mecanismo do IE, o mecanismo do Chrome) implementarão essa tarefa de maneira diferente.
Suas implementações exclusivas, obviamente, NÃO são escritas em uma linguagem declarativa, mas em uma processual como Assembly, C, C ++, Java, JavaScript ou Python. Esse código é um conjunto de etapas a serem executadas passo a passo (e pode incluir chamadas de função). Pode fazer coisas como interpolar valores de pixel e renderizar na tela.
Sinto muito, mas devo discordar de muitas das outras respostas. Eu gostaria de parar com esse equívoco confuso da definição de programação declarativa.
Definição
A transparência referencial (RT) das subexpressões é o único atributo necessário de uma expressão de programação declarativa , porque é o único atributo que não é compartilhado com a programação imperativa.
Outros atributos citados da programação declarativa derivam desse RT. Clique no hiperlink acima para obter uma explicação detalhada.
Exemplo de planilha
Duas respostas mencionaram a programação de planilhas. Nos casos em que a programação da planilha (também conhecida como fórmulas) não acessa o estado global mutável , é uma programação declarativa. Isso ocorre porque os valores das células mutáveis são a entrada e saída monolíticas do main()
(o programa inteiro). Os novos valores não são gravados nas células após a execução de cada fórmula, portanto, não são mutáveis durante a vida útil do programa declarativo (execução de todas as fórmulas na planilha). Assim, uma em relação à outra, as fórmulas veem essas células mutáveis como imutáveis. Uma função RT pode acessar o estado global imutável (e também o estado local mutável ).
Portanto, a capacidade de alterar os valores nas células quando o programa termina (como saída de main()
) não os torna valores armazenados mutáveis no contexto das regras. A principal diferença é que os valores das células não são atualizados após a execução de cada fórmula da planilha, portanto, a ordem de execução das fórmulas não importa. Os valores das células são atualizados após a execução de todas as fórmulas declarativas.
A programação declarativa é a imagem, onde a programação imperativa é instruções para pintar essa imagem.
Você está escrevendo em estilo declarativo se está "dizendo o que é", em vez de descrever as etapas que o computador deve seguir para chegar onde você deseja.
Ao usar XML para marcar dados, você usa programação declarativa porque está dizendo "Esta é uma pessoa, é um aniversário e lá é um endereço".
Alguns exemplos de onde a programação declarativa e a imperativa se combinam para obter um efeito maior:
O Windows Presentation Foundation usa a sintaxe XML declarativa para descrever como é a interface do usuário e quais são os relacionamentos (ligações) entre controles e estruturas de dados subjacentes.
Os arquivos de configuração estruturada usam sintaxe declarativa (tão simples quanto os pares "chave = valor") para identificar o significado de uma sequência ou valor de dados.
O HTML marca o texto com tags que descrevem qual o papel de cada parte do texto em relação ao documento inteiro.
Programação declarativa é a programação com declarações, ou seja, sentenças declarativas. As frases declarativas têm várias propriedades que as distinguem das frases imperativas. Em particular, as declarações são:
Um ponto relevante é que todas essas são propriedades estruturais e são ortogonais ao objeto. Declarativo não é sobre "O que vs. Como" . Podemos declarar (representar e restringir) um "como" tão facilmente quanto declaramos um "o quê" . Declarativo é sobre estrutura, não conteúdo. A programação declarativa tem um impacto significativo na forma como abstraímos e refatoramos nosso código e como o modificamos em subprogramas, mas não tanto no modelo de domínio.
Frequentemente, podemos converter de imperativo em declarativo adicionando contexto. Por exemplo, em "Vire à esquerda. (... espere ...) Vire à direita." para "Bob vira à esquerda no cruzamento de Foo e Bar às 11:01. Bob vira à direita no cruzamento de Bar e Baz às 11:06." Observe que, no último caso, as sentenças são idempotentes e comutativas, enquanto no primeiro caso, reorganizar ou repetir as sentenças alteraria severamente o significado do programa.
Em relação à monotônica , as declarações podem adicionar restrições que subtraem possibilidades . Mas restrições ainda adicionam informações (mais precisamente, restrições são informações). Se precisarmos de declarações que variam no tempo, é típico modelar isso com semântica temporal explícita - por exemplo, de "a bola é chata" a "a bola é chata no tempo T". Se tivermos duas declarações contraditórias, teremos um sistema declarativo inconsistente, embora isso possa ser resolvido através da introdução de restrições suaves (prioridades, probabilidades etc.) ou alavancando uma lógica paraconsistente.
imagine uma página do excel. Com colunas preenchidas com fórmulas para calcular sua declaração de imposto.
Toda a lógica é feita declarada nas células, a ordem do cálculo é determinada pela própria fórmula e não processualmente.
Esse é o tipo de programação declarativa. Você declara o espaço do problema e a solução em vez do fluxo do programa.
Prolog é a única linguagem declarativa que eu uso. Isso requer um tipo diferente de pensamento, mas é bom aprender apenas para expô-lo a algo diferente da linguagem de programação processual típica.
Refinei minha compreensão da programação declarativa desde dezembro de 2011, quando forneci uma resposta a esta pergunta. Aqui segue o meu entendimento atual.
A versão longa do meu entendimento (pesquisa) está detalhada neste link , que você deve ler para obter um entendimento profundo do resumo que fornecerei abaixo.
A programação imperativa é onde o estado mutável é armazenado e lido, portanto, a ordem e / ou duplicação das instruções do programa podem alterar o comportamento (semântica) do programa (e até causar um erro, ou seja, comportamento não intencional).
No sentido mais ingênuo e extremo (que afirmei em minha resposta anterior), a programação declarativa (DP) está evitando todo estado mutável armazenado, portanto, a ordenação e / ou duplicação das instruções do programa NÃO podem alterar o comportamento (semântica) do programa .
No entanto, essa definição extrema não seria muito útil no mundo real, pois quase todos os programas envolvem um estado mutável armazenado. O exemplo da planilha está em conformidade com essa definição extrema de DP, porque todo o código do programa é executado até a conclusão com uma cópia estática do estado de entrada, antes que os novos estados sejam armazenados. Então, se qualquer estado for alterado, isso será repetido. Mas a maioria dos programas do mundo real não pode se limitar a um modelo tão monolítico de mudanças de estado.
Uma definição mais útil de DP é que a ordem e / ou duplicação das instruções de programação não altera nenhuma semântica opaca. Em outras palavras, não há alterações aleatórias ocultas na semântica - quaisquer alterações na ordem e / ou duplicação das instruções do programa causam apenas alterações intencionais e transparentes no comportamento do programa.
O próximo passo seria falar sobre quais modelos ou paradigmas de programação auxiliam no PD, mas essa não é a questão aqui.
Functional programming
é uma palavra da moda nos dias de hoje que é essencialmente um subconjunto de programação declarativa. O LINQ na linguagem C # é um elemento da programação funcional quando a própria linguagem é imperativa por natureza. Portanto, o C # se torna um tipo de híbrido, seguindo essa definição.
É um método de programação baseado em descrever o que algo deve fazer ou ser, em vez de descrever como deve funcionar.
Em outras palavras, você não escreve algoritmos feitos de expressões, apenas define como deseja que as coisas sejam. Dois bons exemplos são HTML e WPF.
Este artigo da Wikipedia é uma boa visão geral: http://en.wikipedia.org/wiki/Declarative_programming
Desde que escrevi minha resposta anterior, formulei uma nova definição da propriedade declarativa que é citada abaixo. Também defini programação imperativa como propriedade dupla.
Essa definição é superior à que eu forneci na minha resposta anterior, porque é sucinta e é mais geral. Mas pode ser mais difícil grunhir, porque a implicação dos teoremas da incompletude aplicáveis à programação e à vida em geral é difícil para os humanos compreenderem.
A explicação citada da definição discute o papel da pura programação funcional na programação declarativa.
Declarativo vs. Imperativo
A propriedade declarativa é estranha, obtusa e difícil de capturar em uma definição tecnicamente precisa que permanece geral e não ambígua, porque é uma noção ingênua que podemos declarar o significado (também conhecido como semântica) do programa sem incorrer em efeitos colaterais não intencionais. Existe uma tensão inerente entre a expressão do significado e a prevenção de efeitos não intencionais, e essa tensão realmente deriva dos teoremas da incompletude da programação e do nosso universo.
É simplista demais, tecnicamente impreciso e muitas vezes ambíguo definir declarativo como " o que fazer " e imperativo como " como fazer " . Um caso ambíguo é o "o quê " é o " como " em um programa que gera um programa - um compilador.
Evidentemente, a recursão ilimitada que completa uma linguagem de Turing também está analogamente na semântica - não apenas na estrutura sintática da avaliação (também conhecida como semântica operacional). Este é logicamente um exemplo análogo ao teorema de Gödel - " qualquer sistema completo de axiomas também é inconsistente ". Pondere sobre a estranheza contraditória dessa citação! Também é um exemplo que demonstra como a expressão da semântica não tem um limite comprovável; portanto, não podemos provar 2 que um programa (e analogicamente sua semântica) interrompe o teorema de Halting.
Os teoremas da incompletude derivam da natureza fundamental do nosso universo, que, como afirmado na Segunda Lei da Termodinâmica, é " a entropia (também conhecida como o número de possibilidades independentes) está tendendo ao máximo para sempre ". A codificação e o design de um programa nunca terminam - ele está vivo! - porque tenta atender a uma necessidade do mundo real, e a semântica do mundo real está sempre mudando e tendendo a mais possibilidades. Os humanos nunca param de descobrir coisas novas (incluindo erros em programas ;-).
Para capturar com precisão e tecnicamente essa noção desejada acima mencionada dentro desse universo estranho que não tem limites (pense nisso! Não existe "fora" do nosso universo)), requer uma definição concisa, mas enganosamente não-simples, que soará incorreta até que seja explicada profundamente.
Definição:
A propriedade declarativa é onde pode existir apenas um conjunto possível de instruções que podem expressar cada semântica modular específica.
A propriedade imperativa 3 é a dupla, onde a semântica é inconsistente na composição e / ou pode ser expressa com variações de conjuntos de declarações.
Essa definição de declarativo é distintamente local no escopo semântico, o que significa que exige que uma semântica modular mantenha seu significado consistente, independentemente de onde e como é instanciada e empregada no escopo global . Assim, cada semântica modular declarativa deve ser intrinsecamente ortogonal a todos os outros possíveis - e não um algoritmo ou modelo global impossível (devido aos teoremas da incompletude) para testemunhar consistência, que também é o ponto de “ Mais nem sempre é melhor ” por Robert Harper, professor de Ciência da Computação na Universidade Carnegie Mellon, um dos designers da Standard ML.
Exemplos destes semântica declarativa modulares incluem categoria functors teoria, por exemplo, a
Applicative
, tipagem nominal, espaços de nomes, campos chamados, e com relação ao nível operacional dos semântica então programação funcional puro.Assim, linguagens declarativas bem projetadas podem expressar mais claramente o significado , embora com alguma perda de generalidade no que pode ser expresso, mas um ganho no que pode ser expresso com consistência intrínseca.
Um exemplo da definição mencionada acima é o conjunto de fórmulas nas células de um programa de planilhas - que não devem ter o mesmo significado quando movidas para diferentes células de coluna e linha, ou seja, os identificadores de célula foram alterados. Os identificadores de célula fazem parte e não são supérfluos para o significado pretendido. Portanto, cada resultado da planilha é gravado exclusivamente nos identificadores de célula em um conjunto de fórmulas. A semântica modular consistente, neste caso, é o uso de identificadores de célula como entrada e saída de funções puras para fórmulas de células (veja abaixo).
A Linguagem de Marcação de Hipertexto, também conhecida como HTML - a linguagem para páginas da Web estáticas - é um exemplo de uma linguagem declarativa altamente (mas não perfeitamente 3 ) que (pelo menos antes do HTML 5) não tinha capacidade para expressar comportamento dinâmico. Talvez o HTML seja a linguagem mais fácil de aprender. Para comportamento dinâmico, uma linguagem de script imperativa, como JavaScript, geralmente era combinada com HTML. HTML sem JavaScript se encaixa na definição declarativa porque cada tipo nominal (ou seja, as tags) mantém seu significado consistente sob composição dentro das regras da sintaxe.
Uma definição concorrente para declarativa são as propriedades comutativas e idempotentes das declarações semânticas, ou seja, essas declarações podem ser reordenadas e duplicadas sem alterar o significado. Por exemplo, instruções que atribuem valores a campos nomeados podem ser reordenadas e duplicadas sem alterar o significado do programa, se esses nomes forem modulares, por escrito, em qualquer ordem implícita. Às vezes, os nomes implicam uma ordem, por exemplo, os identificadores de célula incluem suas posições de coluna e linha - mover um total na planilha altera seu significado. Caso contrário, essas propriedades exigem implicitamente mundialconsistência da semântica. Geralmente é impossível projetar a semântica das instruções para que elas permaneçam consistentes se ordenadas ou duplicadas aleatoriamente, porque ordem e duplicação são intrínsecas à semântica. Por exemplo, as declarações "Foo existe" (ou construção) e "Foo não existe" (e destruição). Se considerarmos a inconsistência aleatória endêmica da semântica pretendida, aceitaremos essa definição como suficientemente geral para a propriedade declarativa. Em essência, essa definição é vazia como uma definição generalizada, porque tenta tornar a consistência ortogonal à semântica, ou seja, desafiar o fato de que o universo da semântica é dinamicamente ilimitado e não pode ser capturado em um paradigma de coerência global .
Exigir as propriedades comutativas e idempotentes para a (ordem de avaliação estrutural da) semântica operacional de nível inferior converte a semântica operacional em uma semântica modular localizada declarativa , por exemplo, programação funcional pura (incluindo recursão em vez de loops imperativos). Então, a ordem operacional dos detalhes da implementação não afeta (ou seja, espalha-se globalmente ) a consistência da semântica de nível superior. Por exemplo, a ordem de avaliação (e teoricamente também a duplicação) das fórmulas da planilha não importa, porque as saídas não são copiadas para as entradas até que todas as saídas tenham sido calculadas, ou seja, análogas às funções puras.
C, Java, C ++, C #, PHP e JavaScript não são particularmente declarativos. A sintaxe de Copute e a sintaxe do Python são mais declarativamente acopladas aos resultados pretendidos , ou seja, semântica sintática consistente que elimina o estranho, de modo que se possa compreender prontamente o código depois de esquecê-lo. Copute e Haskell reforçam o determinismo da semântica operacional e incentivam " não se repita " (DRY), porque eles permitem apenas o paradigma funcional puro.
2 Mesmo onde podemos provar a semântica de um programa, por exemplo, com a linguagem Coq, isso é limitado à semântica expressa na digitação , e a digitação nunca pode capturar toda a semântica de um programa - nem mesmo para idiomas que são Se Turing não estiver completo, por exemplo, com HTML + CSS, é possível expressar combinações inconsistentes que, portanto, têm semântica indefinida.
3 Muitas explicações afirmam incorretamente que apenas a programação imperativa ordenou declarações sintaticamente. Esclarei essa confusão entre programação imperativa e programação funcional . Por exemplo, a ordem das instruções HTML não reduz a consistência de seus significados.
Edit: Postei o seguinte comentário no blog de Robert Harper:
na programação funcional ... o intervalo de variação de uma variável é do tipo
Dependendo de como se distingue a programação funcional da imperativa, o seu 'atribuível' em um programa imperativo também pode ter um tipo que limita sua variabilidade.
A única definição não confusa que atualmente aprecio para programação funcional é a) funções como objetos e tipos de primeira classe, b) preferência pela recursão sobre loops e / ou c) funções puras - ou seja, funções que não afetam a semântica desejada do programa quando memorizado ( portanto, a programação funcional perfeitamente pura não existe em uma semântica denotacional de uso geral devido a impactos da semântica operacional, por exemplo, alocação de memória ).
A propriedade idempotente de uma função pura significa que a chamada de função em suas variáveis pode ser substituída por seu valor, o que geralmente não é o caso dos argumentos de um procedimento imperativo. As funções puras parecem ser declarativas para as transições de estado não compostas entre os tipos de entrada e resultado.
Mas a composição de funções puras não mantém essa consistência, porque é possível modelar um processo imperativo de efeito colateral (estado global) em uma linguagem de programação funcional pura, por exemplo, o IOMonad de Haskell e, além disso, é inteiramente impossível impedir isso. qualquer linguagem de programação funcional pura e completa de Turing.
Como escrevi em 2012, que parece o consenso semelhante de comentários em seu blog recente , essa programação declarativa é uma tentativa de capturar a noção de que a semântica pretendida nunca é opaca. Exemplos de semânticas opacas são dependência da ordem, dependência da eliminação de semânticas de nível superior na camada semântica operacional (por exemplo, projeções não são conversões e genéricos reificados limitam a semântica de nível superior ) e dependência de valores variáveis que não podem ser verificados (comprovado correto) pela linguagem de programação.
Assim, concluí que apenas linguagens completas não-Turing podem ser declarativas.
Assim, um atributo inequívoco e distinto de uma linguagem declarativa pode ser que sua saída pode ser comprovada como obedecendo a um conjunto enumerável de regras generativas. Por exemplo, para qualquer programa HTML específico (ignorando as diferenças nas maneiras como os intérpretes divergem) que não está com script (ou seja, não está completo com Turing), sua variabilidade de saída pode ser enumerável. Ou, mais sucintamente, um programa HTML é uma função pura de sua variabilidade. O mesmo programa de planilha é uma função pura de suas variáveis de entrada.
Portanto, parece-me que as linguagens declarativas são a antítese da recursão ilimitada , ou seja, pelo segundo teorema da incompletude de Gödel, os teoremas auto-referenciais não podem ser provados.
Lesie Lamport escreveu um conto de fadas sobre como Euclides poderia ter trabalhado com os teoremas da incompletude de Gödel aplicados às provas de matemática no contexto da linguagem de programação, à congruência entre tipos e lógica (correspondência de Curry-Howard, etc.).
A programação declarativa é "o ato de programar em linguagens que se adaptam ao modelo mental do desenvolvedor e não ao modelo operacional da máquina".
A diferença entre programação declarativa e imperativa é bem ilustrada pelo problema de analisar dados estruturados.
Um programa imperativo usaria funções recursivas mutuamente para consumir entrada e gerar dados. Um programa declarativo expressaria uma gramática que define a estrutura dos dados para que possam ser analisados.
A diferença entre essas duas abordagens é que o programa declarativo cria uma nova linguagem que é mais intimamente mapeada para o modelo mental do problema do que a linguagem hospedeira.
Eu explicaria isso como DP é uma maneira de expressar
... e onde existe um mecanismo de dedução geralmente trabalhando com um algoritmo de unificação para encontrar os objetivos.
Até onde eu sei, ele começou a ser usado para descrever sistemas de programação como o Prolog, porque o prólogo é (supostamente) sobre declarar as coisas de uma maneira abstrata.
Cada vez mais significa muito pouco, pois possui a definição dada pelos usuários acima. Deve ficar claro que existe um abismo entre a programação declarativa de Haskell e a programação declarativa do HTML.
Alguns outros exemplos de programação declarativa:
A programação declarativa é boa porque pode ajudar a simplificar seu modelo mental * de código e porque pode eventualmente ser mais escalável.
Por exemplo, digamos que você tenha uma função que faz algo para cada elemento em uma matriz ou lista. O código tradicional ficaria assim:
foreach (object item in MyList)
{
DoSomething(item);
}
Não é grande coisa lá. Mas e se você usar a sintaxe mais declarativa e definir DoSomething () como uma ação? Então você pode dizer assim:
MyList.ForEach(DoSometing);
É claro que isso é mais conciso. Mas tenho certeza que você tem mais preocupações do que apenas salvar duas linhas de código aqui e ali. Desempenho, por exemplo. Da maneira antiga, o processamento tinha que ser feito em sequência. E se o método .ForEach () tivesse uma maneira de sinalizar que ele poderia lidar com o processamento em paralelo, automaticamente? Agora, de repente, você tornou seu código multiencadeado de uma maneira muito segura e mudou apenas uma linha de código. E, de fato, há uma extensão para .Net que permite fazer exatamente isso.
Depende de como você envia a resposta ao texto. No geral, você pode ver o programa sob uma determinada visualização, mas depende de qual ângulo você olha para o problema. Vou começar com o programa: Dim Bus, Car, Time, Height As Integr
Novamente, depende de qual é o problema em geral. Talvez você precise reduzi-lo devido ao programa. Espero que isso ajude e precise do feedback, se não. Obrigado.