Как объявить ограничение hasEq?

Я только начинаю с F*, что означает, что я написал несколько строк вместе с учебником. Пока что это действительно интересно, и я бы хотел продолжить обучение.

Первое, что я попытался сделать самостоятельно, - написать тип, представляющий непустой список. Это была моя попытка:

type nonEmptyList 'a = l : (list 'a) { l <> [] }

Но я получаю ошибку

Не удалось проверить неявный аргумент: проверка подтипа не удалась; ожидаемый тип (a#6468:Type{(hasEq a@0)}); получил тип Тип

Я знаю, что я на правильном пути, потому что, если я ограничу свой тип списка, содержащий строки, это работает:

type nonEmptyList = l : (list string) { l <> [] }

Я предполагаю, что это означает, что l <> [] в исходном примере недействительно, потому что я не указал, что 'a должен поддерживать равенство. Проблема в том, что я не могу понять, как это сделать. Я думаю, это как-то связано с более высоким hasEq, но пытается такие вещи, как:

type nonEmptyList 'a = l : (list 'a) { hasEq 'a /\ l <> [] }

не получил меня никуда. Учебник не распространяется hasEq и я не могу найти ничего полезного в примерах репозитория GitHub, так что теперь я застрял.

2 ответа

Решение

Вы правильно определили проблему здесь. Тип 'a что вы использовали в определении nonEmptyList не указано и, следовательно, не может поддерживать равенство. Ваша интуиция верна, вы должны сказать F*, что 'a это тип, который имеет равенство, добавив уточнение к нему:

Для этого вы можете написать следующее:

type nonEmptyList (a:Type{hasEq a}) = l : (list a) { l <> [] }

Обратите внимание, что связующее, которое я использовал для этого типа, a и не 'a, Это может вызвать синтаксическую ошибку, это имеет больше смысла, потому что это больше не "любой" тип. Также обратите внимание, что вы можете быть еще более точным и указать юниверс типа a как Type0 если нужно.

Ваш анализ действительно правильный, и принятый ответ дает правильное решение в целом.

Однако для вашего конкретного примера вам не нужно решаемое равенство в элементах списка: вы можете просто использовать (list 'a){ ~ (List.isEmpty l) },

Для справки вот определение isEmpty:

(** [isEmpty l] returns [true] if and only if [l] is empty  *)
val isEmpty: list 'a -> Tot bool
let isEmpty l = match l with
  | [] -> true
  | _ -> false
Другие вопросы по тегам