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
é apenas um tipo, portanto deve ser uma proposição. OK, igualmente IsNat n
é apenas um tipo, portanto deve ser uma proposição. Devo estar "em minha honra" para não deixar n
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 de n
é de um 'tipo' particular, também conhecido como 'tipo' na lógica. Então eu estou indo além de simplesmente tipado λ-calc (?)
IsNat
não fazer uma proposição a partir de um termo, é fazer uma proposição a partir de uma proposição .