Lean , 66 байт
def s:_->nat->nat|(m+1)(n+1):=(n+1)*(s m n+s m(n+1))|0 0:=1|_ _:=0
Попробуйте онлайн!
Доказательство правильности
Попробуйте онлайн!
объяснение
Давайте раскроем функцию:
def s : nat->nat->nat
| (m+1) (n+1) := (n+1)*(s m n + s m (n+1))
| 0 0 := 1
| _ _ := 0
Функция определяется сопоставлением с образцом и рекурсией, оба из которых имеют встроенную поддержку.
Мы определяем s(m+1, n+1) = (n+1) * (s(m, n) + s(m, n+1)и s(0, 0) = 1, который оставляет открытым, s(m+1, 0)и s(0, n+1), оба из которых определены 0в последнем случае.
Постные использует синтаксис lamdba исчисления, так s m nэто s(m, n).
Теперь доказательство правильности: я сформулировал это двумя способами:
def correctness : ∀ m n, fin (s m n) ≃ { f : fin m → fin n // function.surjective f } :=
λ m, nat.rec_on m (λ n, nat.cases_on n s_zero_zero (λ n, s_zero_succ n)) $
λ m ih n, nat.cases_on n (s_succ_zero m) $ λ n,
calc fin (s (nat.succ m) (nat.succ n))
≃ (fin (n + 1) × (fin (s m n + s m (n + 1)))) :
(fin_prod _ _).symm
... ≃ (fin (n + 1) × (fin (s m n) ⊕ fin (s m (n + 1)))) :
equiv.prod_congr (equiv.refl _) (fin_sum _ _).symm
... ≃ (fin (n + 1) × ({f : fin m → fin n // function.surjective f} ⊕
{f : fin m → fin (n + 1) // function.surjective f})) :
equiv.prod_congr (equiv.refl _) (equiv.sum_congr (ih n) (ih (n + 1)))
... ≃ {f // function.surjective f} : s_aux m n
def correctness_2 (m n : nat) : s m n = fintype.card { f : fin m → fin n // function.surjective f } :=
by rw fintype.of_equiv_card (correctness m n); simp
Первый - это то, что на самом деле происходит: биекция между [0 ... s(m, n)-1]и наложения [0 ... m-1]на [0 ... n-1].
Второй, как обычно говорят, это s(m, n)кардинальность выводов [0 ... m-1]на [0 ... n-1].
Lean использует теорию типов в качестве своей основы (вместо теории множеств). В теории типов каждый объект имеет свойственный ему тип. natтип натуральных чисел, а утверждение, которое 0является натуральным числом, выражается как 0 : nat. Мы говорим , что 0это типа nat, и natимеет 0как житель.
Предложения (утверждения / утверждения) также являются типами: их обитатель является доказательством предложения.
defМы собираемся ввести определение (потому что биекция - это действительно функция, а не просто суждение).
correctness: название определения
∀ m n: для каждого mи n(Lean автоматически делает вывод, что их тип nat, из-за того, что следует).
fin (s m n)это тип натуральных чисел, который меньше, чем s m n. Чтобы сделать обитателя, нужно предоставить натуральное число и доказательство того, что оно меньше, чем s m n.
A ≃ B: биекция между типом Aи типом B. Сказать, что биекция вводит в заблуждение, поскольку на самом деле нужно предоставить обратную функцию.
{ f : fin m → fin n // function.surjective f }тип сюрпризов от fin mдо fin n. Этот синтаксис создает подтип из типа fin m → fin n, то есть типа функций из fin mв fin n. Синтаксис есть { var : base type // proposition about var }.
λ m: ∀ var, proposition / type involving varдействительно функция, которая принимает varв качестве входных данных, поэтому λ mвводит ввод. ∀ m n,это сокращение для∀ m, ∀ n,
nat.rec_on m: сделать рекурсию на m. Чтобы определить что-то для m, определите вещь для, 0а затем с учетом вещи k, построить вещь для k+1. Можно заметить, что это похоже на индукцию, и на самом деле это результат переписки Чёрча-Говарда . Синтаксис есть nat.rec_on var (thing when var is 0) (for all k, given "thing when k is k", build thing when var is "k+1").
Хех, это становится длинным, и я только на третьей линии correctness...