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як останній випадок.
Lean використовує синтаксис обчислення 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...