Вы попали в ужасный угол синтаксиса F *. https://github.com/FStarLang/FStar/issues/1905 Мы обсуждали способы его улучшения.
В частности, F * позволяет связывать имена с типами, которые в некоторых случаях не имеют смысла. В вашем примере имя x
не имеет смысла в x:nat
, который встречается в типе леммы. Он интерпретируется F * как unit -> Lemma nat
: это тип доказательства, показывающего, что тип nat
заселен ... что не особенно интересно. Для справки, один из способов доказать, что неинтересный тип - это
let nat_is_inhabited () : Lemma nat = FStar.Squash.return_squash #nat 0
Теперь к вашему актуальному вопросу о том, как изложить доказательство подтипа. Есть много способов. Один из распространенных способов следующий:
Допустим, у вас есть тип
let tp = x:t { p }
И в какой-то момент у вас есть
let f (x:t) = … assert (q x); let y : tp = x in …
, т. Е. Из-за некоторой контекстной информации который дает вам свойство q x
, которое вы хотите обработать x:t
по типу tp
.
Если вы можете доказать лемму вида
val q_implies_p (x:t) : Lemma (requires q x) (ensures p x)
, тогда позвоните лемма в нужной точке вашего кода, вы можете дать F * и SMT solver достаточно информации, чтобы принять подтип от x:t
до tp
. Например, что-то вроде этого:
let f (x:t) = … assert (q x); q_implies_p x; let y : tp = x in …
Надеюсь, это поможет. Извините за запутанный синтаксис!