Então, eu estou tentando convencer Curry-Howard. (Eu tentei várias vezes, não é gelificante / parece muito abstrato). Para abordar algo concreto, estou trabalhando nos dois tutoriais de Haskell vinculados à wikipedia, especialmente no de Tim Newsham . Também há uma discussão útil quando Newsham postou o tutorial.
(Mas vou ignorar os data
envoltórios de Newsham e Piponi e falar sobre os tipos subjacentes.) Temos o esquema de axiomas de Hilbert (expresso como combinadores S , K ); nós temos proposições como tipos; implicação como função-seta; e Modus Ponens como aplicação de função:
axK :: p -> q -> p
axK = const
axS :: (p -> q -> r) -> (p -> q) -> p -> r
axS f g x = f x (g x)
modPons = ($); infixl 0 `modPons` -- infix Left, cp ($) is Right
Então eu posso derivar a lei de identidade:
ident = axS `modPons` axK `modPons` axK -- (S K K)
-- ident :: p -> p -- inferred
Ter esses tipos como caracteres simples, apenas correspondendo a proposições, parece um pouco sem imaginação. Posso usar mais do sistema de tipos para realmente construir as proposições? Estou pensando:
data IsNat n = IsNat !n -- [Note **]
data Z = Z
axNatZ :: IsNat Z
axNatZ = IsNat Z
data S n = S !n
axNatS :: IsNat n -> IsNat (S n)
axNatS (IsNat n) = IsNat (S n)
twoIsNat = axNatS `modPons` (axNatS `modPons` axNatZ)
-- ===> IsNat (S (S Z))
[Nota **] Estou usando construtores rigorosos, conforme o tópico da discussão, para evitar a introdução de _ | _ .
Onde:
IsNat
é um predicado: fazer uma proposição a partir de um termo.n
é uma variávelS
é uma função, criando um termo a partir de uma variável.Z
é uma constante (função niládica).
Então eu pareço ter incorporado a lógica de predicados (de primeira ordem) (?)
Aprecio que meus tipos não são muito higiênicos; Eu poderia facilmente misturar uma typevar-como-proposição com uma typevar-como-termo. Talvez eu deva usar o Kind
sistema para segregá-los. OTOH meus axiomas teriam que estar espetacularmente errados para chegar a qualquer conclusão.
Eu não expressei:
- quantificador universal: está implícito nos vars livres;
- quant existencial: de fato, as constantes poderiam atuar como existenciais skememised;
- igualdade de termos: usei repetidos tipos de letra em implicações;
- relações: isso parece funcionar, ou é mancada? ...
data PlusNat n m l = PlusNat !n !m !l
axPlusNatZ :: IsNat m -> PlusNat Z m m
axPlusNatZ (IsNat m) = PlusNat Z m m
axPlusNatS :: PlusNat n m l -> PlusNat (S n) m (S l)
axPlusNatS (PlusNat n m l) = PlusNat (S n) m (S l)
plus123 = axPlusNatS `modPons`
(axPlusNatZ `modPons`
(axNatS `modPons` (axNatS `modPons` axNatZ)) )
-- ===> PlusNat (S Z) (S (S Z)) (S (S (S Z)))
Escrever os axiomas é fácil, cortesia dos Teoremas de Wadler de graça! . Escrever as provas é um trabalho árduo. (Vou largar o modPons
e apenas usar o aplicativo de função.)
Isso é realmente alcançar uma lógica? Ou é uma coisa louca? Devo parar antes de causar mais danos ao meu cérebro?
Você precisa de Tipos Dependentes para expressar FOPL em Curry-Howard. Mas eu não pareço estar fazendo isso (?)
IsNat
não fazer uma proposição a partir de um termo, é fazer uma proposição a partir de uma proposição .IsNat
é apenas um tipo, portanto deve ser uma proposição. OK, igualmenteIsNat n
é apenas um tipo, portanto deve ser uma proposição. Devo estar "em minha honra" para não deixarn
escapar na terra da proposição / aparecer como argumento para um conectivo lógico (e foi por isso que falei sobre higiene do tipo). Você ficaria mais feliz se eu usasse a codificação da Igreja para Nats? Eu acho que só estou estendendo λ-calc com construtores no nível do tipo, mesmo que Haskell ao nível prazo (?)n
seja uma proposição : está dizendo 'eu sou habitado'. O que não é mais do que qualquer typevar está dizendo sob CH.IsNat n
está dizendo / testemunhando: além disso, o habitante den
é de um 'tipo' particular, também conhecido como 'tipo' na lógica. Então eu estou indo além de simplesmente tipado λ-calc (?)Respostas:
Para explicar por que não me sinto à vontade com os
data
invólucros de Newsham e (especialmente) de Piponi ... (Isso será mais uma pergunta do que uma resposta, mas talvez isso funcione para explicar o que há de errado com o meu,IsNat
mesmo que pareça muito com o Newsham. )A página 17 de Piponi possui:
Não vejo tipos aqui. Ortografia de um construtor de dados
:->
não faz com que ela funcione como seta; e a ortografia de um construtor de dadosMP
(para o Modus Ponens) não faz com que ele funcione como aplicativo. Há um operador de 'construtor inteligente'(@@)
paraMP
, mas que não se aplica nenhuma função: ele meramente faz correspondência de padrão no:->
construtor.Newsham possui (começarei com a seção Implication / Modus Ponens):
Parece mais com isso: temos tipos, setas de função, aplicação de função
impElim
. O construtor de tipos,Imp
com suas regras de injeção e eliminação, reflete as estruturas das árvores de prova no isomorfismo Lectures on Curry-Howard . Mas estou nervoso: por queImp
precisa de um construtor de tipos e de dados? Mais uma vez, ortografia como:=>
não faz disso uma seta de função. Por que todos essesProp
construtores de embrulhar e desembrulhar ? Por que não é simplesProp (p -> q)
?Então, quando olho para a seção 'Conjunção' (que realmente vem primeiro):
Essas
Elim
funções não usam aplicativo de função. Eles meramente correspondem aos construtores. Não há estrutura implicacional para a conjunção: confiamos inteiramente que o 'programador' usou apenas aandInj
regra para criar um tipo(p :/\ q)
.Então, quando Newsham chega à comutatividade da conjunção:
E reivindicações
Eu simplesmente discordo:
commuteAnd
não contar com a estrutura interna do:/\
construtor de tipo.andElim
s fazer "espiada" na estrutura.Eu esperaria que pudéssemos provar a comutatividade da conjunção a partir de sua definição, sem precisar de um axioma para dizer isso (?)
OK, se estou sendo tão purista, o que espero? Isso para conjunção é baseado na codificação da Igreja para par:
Agora eu posso escrever
commuteAnd
usando o aplicativo de função 'adequada':Essa definição de função é a mesma que a de Newsham. Mas eu comentei a assinatura porque o tipo inferido de GHC não é suficientemente geral. Ele quer
Prop ((p -> p -> p) -> p) -> ((p -> p -> p) -> p)
. O que é apenas uma variação sofisticada da lei de identidade.Edit: (Após o primeiro comentário de @DerekElkins aqui.) Recuse tudo isso:
Eu preciso de um tipo de classificação mais alta, mas não impredicativo. E não no tipo para,
Conj
mas paracommuteAnd
ESTÁ BEM. Felizmente, posso trocar argumentos ad infinitum.
[Fim da edição]
Então, minha pergunta: se é legítimo o que Newsham está fazendo com construtores de aninhamento e correspondência de padrões em todos os lugares, o que não é legítimo na minha
IsNat
correspondência de padrões e?fonte
Proposition
eProof
não são exemplos da correspondência de Curry-Howard em ação. Esses apenas formam um sistema simples de prova no estilo LCF. A correspondência Curry-Howard é testemunhado pelacompile
função (embora a maior parte do trabalho é feito por(^)
eshow
) que transforma essesProposition
s eProof
s em código Haskell. Como para o código de Newsham, os invólucros não fazem diferença(:=>)
é essencialmente(->)
. Ele apenas os adiciona (como afirma explicitamente) para que ele possa trocar uma implementação diferente e não trivial posteriormente.(:=>)
é implementado como(->)
. Mas um modelo / simulação de uma lógica, precisa de uma validação do intérprete (?). Por que não posso expressar diretamente em Haskell(->)
?(^)
para lidar com o clássico. OK, vou tentar o seushow
para gerar código Haskell e ver como isso difere. (Também tentarei descobrir como ele está apresentandoInteger
.) Estou tentando usar um mínimo de máquinas Haskell, por medo de apresentar_|_
algum lugar e minar "programas são provas".