Por que as linguagens não incluem implicação como um operador lógico?

60

Pode ser uma pergunta estranha, mas por que não há implicação como operador lógico em muitas linguagens (Java, C, C ++, Python Haskell - embora, como a última tenha definido os usuários, os operadores definidos sejam triviais para adicioná-lo)? Acho a implicação lógica muito mais clara para escrever (particularmente em afirmações ou expressões semelhantes a afirmações) e depois negação com ou:

encrypt(buf, key, mode, iv = null) {
    assert (mode != ECB --> iv != null);
    assert (mode == ECB || iv != null);
    assert (implies(mode != ECB, iv != null)); // User-defined function
}
Maciej Piechotka
fonte
28
Porque não foi colocado em C; se tivesse sido colocado, C ++, Java e C # o teriam.
M3th0dman
4
Mas C não o possui, por sua vez, porque não é uma parte comum da linguagem assembly. Considerando que todos os conjuntos de instruções que eu conheço incluem AND, OR e não, não sei de nenhum que incluem implica - sem dúvida alguém estará junto para me dizer de algum conjunto de instruções obscuro que faz pouco tempo ...
Jack Aidley
4
Talvez tenha sido considerado redundante porque (1) é menos primitivo que "^", "v", "~", (2) economiza muito pouca digitação, pois "A => B" é equivalente a "~ A v B" .
Giorgio
4
Idiomas que lidam com construções lógicas têm mais probabilidade de tê-lo. Principalmente entre estes é o prólogo
9
Estou surpreso que você ache que o assertnúmero 1 é mais claro que o número 2. Eu olho para o número 1 por algum tempo e ainda não consigo ver como seu comportamento pode ser considerado intuitivo. (especialmente com o extra de !=inversão da lógica)
Chris Burt-Brown

Respostas:

61

Pode ser útil ter algumas vezes, sem dúvida. Vários pontos argumentam contra esse operador:

  • Os personagens -e >são valiosos, tanto isolados quanto combinados. Muitos idiomas já os usam para significar outras coisas. (E muitos não podem usar conjuntos de caracteres unicode para sua sintaxe.)
  • A implicação é muito contra-intuitiva, mesmo para pessoas que pensam na lógica, como programadores. O fato de três das quatro entradas da tabela verdade serem truesurpreendentes para muitas pessoas.
  • Todos os outros operadores lógicos são simétricos, o que abriria ->uma exceção para a ortogonalidade.
  • Ao mesmo tempo, existe uma solução fácil: use operadores !e ||.
  • A implicação é usada muito menos frequentemente que a lógica and/ or.

Provavelmente é por isso que hoje o operador é raro. Certamente isso poderia se tornar mais comum, à medida que novas linguagens dinâmicas usam o Unicode para tudo e a sobrecarga do operador se torna mais elegante novamente.

Kilian Foth
fonte
22
Seu primeiro ponto apenas argumenta contra o uso de '->' como o símbolo do operador, e não contra realmente o operador. Os outros são bons pontos.
AShelly
14
"Ao mesmo tempo, existe uma solução fácil: use! E &&.": De fato, a maneira mais simples de simular "->" (ou "=>", como é mais comum em Matemática), é usar !e ||, not !e &&: A -> Bé equivalente ao !A || Bque é equivalente a !(A && !B).
Giorgio
22
"O fato de três das quatro entradas da tabela verdade serem verdadeiras surpreende muitas pessoas". Wat. Eu sei que outro operador com o mesmo recurso que é usado com bastante freqüência ...
l0b0
9
@ l0b0, sou um programador que estudou CS, mas foi há muito tempo. Eu tinha esquecido que "implica" é uma operação formal com dois operandos que retorna um valor de verdade, então, a princípio, fiquei confuso com a natureza dessa pergunta. No discurso cotidiano, eu só uso "implica" quando o primeiro operando já é verdadeiro ("X é verdadeiro, então Y deve ser verdadeiro"). Depois de um minuto, lembrei como o formal "implica" funciona, mas o fato permanece - mesmo para alguém que estudou lógica formal, a intenção não estava clara para mim. E se eu nunca tivesse estudado, nem teria feito sentido.
Ben Lee
5
(a) Em C -> é usado como operador. Ninguém reclama disso. Eu usaria => de qualquer maneira. (b) Contra-intuitivo para quem? A definição de implicação é apenas isso, uma definição. (c) a subtração não é comutativa. Ninguém reclama disso. (d) Eu acho que você quer dizer! e ||. Por causa da precedência (e) também são frequentemente necessários. O mesmo argumento pode ser usado contra o && ou ||; faça sua escolha. (e) Talvez seja porque não está na maioria dos idiomas. Muitos usos de || poderia ser concisa e (pelo menos para mim) intuitivamente substituído por implicação.
Theodore Norvell
54

Eu acredito que a resposta está nos fundamentos matemáticos . A implicação é geralmente considerada e definida como uma operação derivada, e não elementar, de álgebras booleanas. As linguagens de programação seguem esta convenção.

Esta é a Proposição I do Capítulo II de Uma Investigação das Leis do Pensamento de George Boole (1854) :

Todas as operações da linguagem, como instrumento de raciocínio, podem ser conduzidas por um sistema de signos composto pelos seguintes elementos, a saber:

1º. Símbolos literais, como x, y, etc., representando as coisas como sujeitos de nossas concepções.

2nd. Sinais de operação, como +, -, ×, representam aquelas operações da mente pelas quais as concepções das coisas são combinadas ou resolvidas, de modo a formar novas concepções envolvendo os mesmos elementos.

3rd. O sinal de identidade,.

E esses símbolos da Lógica estão em seu uso sujeitos a leis definidas, concordando parcialmente e diferindo parcialmente das leis dos símbolos correspondentes na ciência da Álgebra.

O sinal de Boole + representa a mesma "operação da mente" que hoje reconhecemos como o booleano "ou" e a união de conjuntos. Da mesma forma, os sinais - e × correspondem à nossa negação booleana, complemento de um conjunto, 'b' e 'interseção de conjuntos.

VEM DE ONDE
fonte
+1 - resposta sólida. Álgebra booleana e as simplificações na lógica que ela permite impulsionam muita metodologia de programação. Usar um "implica ..." potencialmente interferiria nas condições "não me importo".
3
1. Isso depende da definição. É possível definir ou como a || b = !(!a && !b)(eu conheci ou como operador derivado na lógica). 2. A razão pela qual isso é feito é geralmente simplificar as provas que eu acredito (sabemos que os operadores derivados são apenas atalhos, portanto não precisamos ter argumentos separados para eles). @ GlenH7: O que "não me importo" condições? a --> bé o mesmo que !a || b.
Maciej Piechotka
3
Também - nós temos outros operadores derivados como xor ( !=) nxor ( ==) ...
Maciej Piechotka
5
Na verdade, você pode derivar tudo de NAND !(a && b)ou NOR !(a || b). Por exemplo, NOT a == a NAND a, a AND b == NOT(a NAND b), a OR b == (NOT a) NAND (NOT b). Porém, fornecer apenas um operador NAND o coloca no domínio das línguas esotéricas (o que se encaixa surpreendentemente bem, dado o nome de usuário do respondente ;-)).
Stefan Majewsky
11
@ Stefan: Você também pode derivar tudo de um IMPL.
Mason Wheeler
37

ATUALIZAÇÃO: Esta questão foi o assunto do meu blog em novembro de 2015 . Obrigado pela pergunta interessante!


Visual Basic 6 (e VBScript) tinha Impe Eqvoperadores. Ninguém os usou. Ambos foram removidos no VB.NET; que eu saiba, ninguém reclamou.

Trabalhei na equipe do compilador do Visual Basic (como estagiário) por um ano inteiro e nunca percebi que o VB ainda tinha esses operadores. Se eu não tivesse sido o cara escrevendo o compilador VBScript e, portanto, tivesse que testar suas implementações, provavelmente não as teria notado. Se o cara da equipe do compilador não souber sobre o recurso e não o usar, isso informará sobre a popularidade e a utilidade do recurso.

Você mencionou idiomas do tipo C. Não posso falar com C ou C ++ ou Java, mas posso falar com C #. Há uma lista de recursos sugeridos pelo usuário para C # literalmente mais longos que o seu braço. Que eu saiba, nenhum usuário jamais propôs esse operador à equipe de C #, e eu examinei essa lista muitas e muitas vezes.

Recursos que existem e não são usados ​​em um idioma e nunca são solicitados em outro são candidatos improváveis ​​para torná-lo em linguagens de programação modernas. Particularmente quando não há bastante tempo e esforço e dinheiro disponível no orçamento para fazer características que as pessoas não querem.

Eric Lippert
fonte
O IMP volta como operador aos dias GWBASIC. Lembro-me de 1979.
zarchasmpgmr
11
Eu li que o IMPL é muito útil para contratos de código. (Que VB não tinha.)
Mason Wheeler
3
Os programadores de VBScript foram provavelmente o grupo com menor probabilidade de usar esse operador. No momento, desejo que o PowerShell tenha um operador implícito para que eu possa implementar mais facilmente e de forma legível alguns [switch]parâmetros de filtro.
11135 brianary
Lembro-me do IMP do DEC BASIC. Não me lembro EQV. O operador que eu sempre desejei seria "e não", o que promoveria o operador do lado direito antes de negá-lo. Assim, 0xABCD12345678ul ~& 0x00200000uproduziria 0xABCD12145678ul em vez de 0x12145678ul.
26715
19

Só posso adivinhar, mas um motivo pode ser que existem soluções alternativas que são bastante simples e legíveis. Vamos considerar o seu exemplo:

if (mode != ECB) assert (iv != null);

assert (mode != ECB --> iv != null);  // <-- that's only one character shorter

Se você precisar de uma expressão, o operador embutido se disponível na maioria dos idiomas (geralmente chamado de operador ternário) pode ser usado. Concedido, isso não é tão elegante quanto A --> B, mas o número de casos de uso pode não justificar a adição (e manutenção!) De outro operador:

assert (mode != ECB ? iv != null : true);
Heinzi
fonte
2
A partir de afirmações - há uma boa razão. O primeiro produzirá (em muitas implementações) a mensagem "falha de asserção: iv! = Null" enquanto a segunda "falha de asserção: modo! = BCE -> iv! = Nulo".
Maciej Piechotka 18/01
2
+1, eu estava prestes a fazer a mesma coisa na pergunta (como não estou muito familiarizado com "implicação", isso nunca aparece no dia-a-dia). A ifafirmação é muito, muito mais clara para quase todos.
Izkata 18/01/2013
12

Eiffel tem implicações

Na verdade, tem ainda mais. Tem um número de operadores semi-estritos, bem como estrito.

A razão pela qual os programadores não usam essas coisas é porque nunca são treinados para saber exatamente o que são, como usá-las e quando usá-las - e também como projetar com elas. Como eles nunca são treinados, nunca pedem isso aos escritores do compilador, e é por isso que o pessoal do compilador não se preocupa em colocar esses mecanismos no compilador. Quando os estudantes de Ciência da Computação e os programadores da Shade-tree começarem a ter uma educação mais abrangente, os compiladores começarão a se atualizar.

Acontece que uma vez que você tenha uma linguagem com esses operadores booleanos e saiba como projetar com eles e usá-los, use-os.

Na Eiffel, o uso da palavra-chave "implica" é bastante proeminente por causa do projeto por contrato, devido à natureza pesada de booleano das asserções de contrato. Existem alguns contratos que só podem ser escritos de forma adequada e eficiente com o operador "implica". Isso então implora o comentário de que idiomas sem contratos são ainda mais sem motivo para examinar, treinar e implementar o uso da implicação.

Acrescente a isso que a maioria dos programadores é "fraca em matemática e lógica" nos diz o restante da história. Mesmo que você tenha muita matemática e lógica em sua educação, quando alguém escolhe uma linguagem que não implementa construções como implicação, então tende a pensar que tais coisas são desnecessárias ou não são úteis. Raramente se questiona a linguagem e entra em uma câmara de eco de: "Bem, o pessoal do compilador não vê a necessidade" e "Bem, os programadores não veem a necessidade" - círculo interminável e vicioso.

Em vez disso, o pessoal do compilador precisa fazer backup da teoria, escrever uma notação de linguagem sugerida ou implícita pela teoria (por exemplo, teoria orientada a objetos), independentemente do que as massas sujas de programadores pensem ou solicitem. A partir daí, professores, professores e outros profissionais precisam treinar habilmente jovens mentes com base na teoria bruta e NÃO em "teoria através da lente da linguagem". Quando isso acontece, as pessoas de repente acordam e percebem o que estão perdendo e o que lhes foi impingido.

Agora - há muita teoria por aí que se disfarça de Orientada a Objetos, mas é apenas OO-através-de-um-vidro-escuro-de-[escolha-seu-idioma]. Não se pode ler a maioria dos livros de "teoria" sobre OO porque eles querem interpretar o que a teoria é através das lentes de alguma linguagem. Totalmente falso e incorreto. Seria como ensinar matemática com base na minha calculadora ou minha régua de cálculo. NÃO - ninguém permite que a realidade ensine a si mesmo e depois usa uma notação para descrever o que se observa - isso é chamado de "ciência". Esse outro mash chamado OO baseado em linguagem X é tão distorcido que mal representa a realidade.

Portanto, afaste-se da linguagem, dê uma olhada na teoria bruta e comece novamente. Não permita que limitações, restrições e trabalhos de pintura de uma linguagem lhe digam qual é a teoria. Simplesmente deixe a realidade da teoria ditar sua própria notação e depois passar daí para a formulação de uma linguagem.

A partir daí, você começará a entender como a implicação e a "implicação" não são apenas úteis, mas elegantes e muito legais!

Tem um bom!

Larry
fonte
7

Python tem um operador de implicação de uma maneira oculta.

O operador menor que ou igual a está sobrecarregado para aceitar valores booleanos. Como resultado, pode-se usá-lo como um operador de implicação.

Prova por exemplo (código Python):

print (False <= False) # This will print True.
print (False <= True)  # This will print True.
print (True <= False)  # This will print False.
print (True <= True)   # This will print True.

Lembre-se de que a tabela verdade do operador de implicação é:

LEFT RIGHT RESULT
F    F     T
F    T     T
T    F     F
T    T     T
Mackenzie
fonte
2
Isso é incrível, mas infelizmente tem as propriedades de rigidez incorretas: f() implies g()não deve avaliar g()se f()é False, mas <=avalia g()neste caso.
21414 Jon Purdy
2
@ Jon Purdy - A rigor, a avaliação de curto-circuito é um recurso opcional dos operadores binários. Portanto, tecnicamente, essa é uma implementação perfeitamente legítima do operador de implicação. Dito isto, duvido muito que Guido van Rossum pretendesse que isso fosse um operador de implicação. Esta é apenas uma peculiaridade de comparar booleanos.
Mackenzie
Claro, eu estava dizendo que é uma observação interessante, mas não é algo que você deve usar em programas reais porque não é um curto-circuito e pode surpreender alguém se eles esperarem did_all_possible_stuff = x.do_required_stuff() and (x.supports_optional_stuff() <= x.do_optional_stuff())funcionar.
21416 Jon Purdy
2
Isso funciona também em C e C ++.
Ben Voigt
5

Eiffel tem um operador "implica" e é muito bom para escrever pré e pós-condições. Isso torna o código mais legível, infelizmente, isso nunca foi uma intenção fundamental para a linguagem C e poucas pessoas usavam o eiffel, de modo que a beleza de "implica" como operador não é bem conhecida.

Lothar
fonte
2

Para mim, o grande problema com implica ocorre quando a condição inicial é falsa; por exemplo: "Se o sol estiver verde, eu sou um morcego." Verdadeiro!

Na lógica formal, apenas trabalha para atribuir "Verdadeiro" ao valor quando a condição da implicação não é atendida. Mas na programação, isso pode levar a resultados contra-intuitivos e surpreendentes.

Na verdade, acho que o exemplo @Heinzi dá acima:

if (sun.color() == "green") then assert(me.species() == "fruitbat")

É muito mais fácil de entender e menos propenso a erros devido ao mal entendimento da lógica.

No contexto dos testes, eu apenas interrompi o momento em que minhas suposições se tornaram falsas:

assert(sun.color() == "green")
assert(me.species() == "fruitbat")

Então, ao ponto de @Eric Lippert, como programador não sei quando usaria um operador implícito. O comportamento "Falso é verdadeiro" parece útil no contexto da lógica matemática e formal, mas pode levar a resultados inesperados na lógica do programa.

...

Ninguém mencionou o comum "?" operador, onde "A? B: true" é o mesmo que "implica". Mas enquanto a lógica formal atribui verdadeiro à condição "else", "?" permite que o desenvolvedor atribua isso explicitamente.

Na lógica formal, usar "true" funciona, mas na programação, se a condição for falsa, a melhor resposta é mais como "null" ou "void" ou "skip", ou talvez até false.

Eu acho que alguém teria que argumentar por que "implica" é um operador mais útil do que declarações "?", "If" ou apenas um fluxo regular de programa.

Roubar
fonte