如何在 Haskell 上实施数学归纳法
How to implement mathematics induction on Haskell
data Nat = Zero | Succ Nat
type Predicate = (Nat -> Bool)
-- forAllNat p = (p n) for every finite defined n :: Nat
implies :: Bool -> Bool -> Bool
implies p q = (not p) || q
basecase :: Predicate -> Bool
basecase p = p Zero
jump :: Predicate -> Predicate
jump p n = implies (p n) (p (Succ n))
indstep :: Predicate -> Bool
indstep p = forallnat (jump p)
问题:
证明如果basecase p
和indstep p
,则forAllNat p
我不明白的是,如果basecase p
和indstep p
,那么forAllNat p
当然应该是True
。
我认为 basecase p
说 P(0)
是正确的,并且
indstep p
说 P(Succ n)
即 P(n+1)
是真的
我们需要证明 P(n)
是真的。
我对吗?
关于如何做到这一点有什么建议吗?
你无法在 Haskell. 内证明这一点 () 语言的类型不够依赖。它是一种编程语言,而不是证明助手。我认为作业可能希望您用铅笔和纸来证明它。
不过你可以在 Agda 中完成。
data Nat : Set where
zero : Nat
suc : Nat -> Nat
Pred : Set -> Set1
Pred A = A -> Set
Universal : {A : Set} -> Pred A -> Set
Universal {A} P = (x : A) -> P x
Base : Pred Nat -> Set
Base P = P zero
Step : Pred Nat -> Set
Step P = (n : Nat) -> P n -> P (suc n)
induction-principle : (P : Pred Nat) -> Base P -> Step P -> Universal P
induction-principle P b s zero = b
induction-principle P b s (suc n) = s n (induction-principle P b s n)
(您可能会认出 induction-principle
是 Nat
的 foldr
。)
当 TypeInType
登陆 GHC 8 时,您可能会得到类似这样的东西。不过它不会很漂亮。
正如 Benjamin Hodgson 指出的那样,您无法在 Haskell 中完全证明这一点。但是,您可以用稍强的先决条件来证明一个命题。我也会忽略 Bool
.
不必要的复杂性
{-# LANGUAGE GADTs, KindSignatures, DataKinds, RankNTypes, ScopedTypeVariables #-}
data Nat = Z | S Nat
data Natty :: Nat -> * where
Zy :: Natty 'Z
Sy :: Natty n -> Natty ('S n)
type Base (p :: Nat -> *) = p 'Z
type Step (p :: Nat -> *) = forall (n :: Nat) . p n -> p ('S n)
induction :: forall (p :: Nat -> *) (n :: Nat) .
Base p -> Step p -> Natty n -> p n
induction b _ Zy = b
induction b s (Sy n) = s (induction b s n)
data Nat = Zero | Succ Nat
type Predicate = (Nat -> Bool)
-- forAllNat p = (p n) for every finite defined n :: Nat
implies :: Bool -> Bool -> Bool
implies p q = (not p) || q
basecase :: Predicate -> Bool
basecase p = p Zero
jump :: Predicate -> Predicate
jump p n = implies (p n) (p (Succ n))
indstep :: Predicate -> Bool
indstep p = forallnat (jump p)
问题:
证明如果basecase p
和indstep p
,则forAllNat p
我不明白的是,如果basecase p
和indstep p
,那么forAllNat p
当然应该是True
。
我认为 basecase p
说 P(0)
是正确的,并且
indstep p
说 P(Succ n)
即 P(n+1)
是真的
我们需要证明 P(n)
是真的。
我对吗?
关于如何做到这一点有什么建议吗?
你无法在 Haskell. 内证明这一点 (
不过你可以在 Agda 中完成。
data Nat : Set where
zero : Nat
suc : Nat -> Nat
Pred : Set -> Set1
Pred A = A -> Set
Universal : {A : Set} -> Pred A -> Set
Universal {A} P = (x : A) -> P x
Base : Pred Nat -> Set
Base P = P zero
Step : Pred Nat -> Set
Step P = (n : Nat) -> P n -> P (suc n)
induction-principle : (P : Pred Nat) -> Base P -> Step P -> Universal P
induction-principle P b s zero = b
induction-principle P b s (suc n) = s n (induction-principle P b s n)
(您可能会认出 induction-principle
是 Nat
的 foldr
。)
当 TypeInType
登陆 GHC 8 时,您可能会得到类似这样的东西。不过它不会很漂亮。
正如 Benjamin Hodgson 指出的那样,您无法在 Haskell 中完全证明这一点。但是,您可以用稍强的先决条件来证明一个命题。我也会忽略 Bool
.
{-# LANGUAGE GADTs, KindSignatures, DataKinds, RankNTypes, ScopedTypeVariables #-}
data Nat = Z | S Nat
data Natty :: Nat -> * where
Zy :: Natty 'Z
Sy :: Natty n -> Natty ('S n)
type Base (p :: Nat -> *) = p 'Z
type Step (p :: Nat -> *) = forall (n :: Nat) . p n -> p ('S n)
induction :: forall (p :: Nat -> *) (n :: Nat) .
Base p -> Step p -> Natty n -> p n
induction b _ Zy = b
induction b s (Sy n) = s (induction b s n)