Любые уловки, чтобы избавиться от шаблонного при построении доказательств абсурдного предиката на перечислениях?
Допустим, у меня есть
data Fruit = Apple | Banana | Grape | Orange | Lemon | {- many others -}
и предикат этого типа,
data WineStock : Fruit -> Type where
CanonicalWine : WineStock Grape
CiderIsWineToo : WineStock Apple
который не подходит для Banana
, Orange
, Lemon
и другие.
Можно сказать, что это определяет WineStock
в качестве предиката Fruit
; WineStock Grape
верно (поскольку мы можем построить значение / доказательство этого типа: CanonicalWine
) так же как WineStock Apple
, но WineStock Banana
ложно, так как этот тип не заселен никакими значениями / доказательствами.
Тогда, как я могу эффективно использовать Not (WineStock Banana)
, Not (WineStock Lemon)
, так далее? Кажется, что для каждого Fruit
кроме конструктора Grape
а также Apple
Я не могу помочь, но должен кодировать дело, разделенное на WineStock
где-то, полный impossible
s:
instance Uninhabited (WineStock Banana) where
uninhabited CanonicalWine impossible
uninhabited CiderIsWineToo impossible
instance Uninhabited (WineStock Lemon) where
uninhabited CanonicalWine impossible
uninhabited CiderIsWineToo impossible
instance Uninhabited (WineStock Orange) where
uninhabited CanonicalWine impossible
uninhabited CiderIsWineToo impossible
Обратите внимание, что:
- код повторяется,
- LoC взорвется, когда определение предиката будет расти, получая больше конструкторов. Просто представьте
Not (Sweet Lemon)
доказательство, если предположить, что вFruit
определение.
Таким образом, этот способ не кажется вполне удовлетворительным, почти нецелесообразным.
Есть ли более элегантные подходы?
1 ответ
@slcv прав: использование функции, которая вычисляет, удовлетворяет ли фрукт свойство или нет, вместо построения различных индуктивных предикатов, позволит вам избавиться от этих издержек.
Вот минимальная настройка:
data Is : (p : a -> Bool) -> a -> Type where
Indeed : p x = True -> Is p x
isnt : {auto eqF : p a = False} -> Is p a -> b
isnt {eqF} (Indeed eqT) = case trans (sym eqF) eqT of
Refl impossible
Is p x
гарантирует, что собственность p
держит элемент x
(Я использовал индуктивный тип, а не псевдоним типа, чтобы Idris не раскрыла его в контексте дыры; так легче читать таким образом).
isnt prf
отклоняет поддельное доказательство prf
всякий раз, когда типограф проверяет p a = False
автоматически (через Refl
или предположение в контексте).
После того, как они у вас есть, вы можете начать определять свои свойства, перечисляя только положительные случаи и добавляя
wineFruit : Fruit -> Bool
wineFruit Grape = True
wineFruit Apple = True
wineFruit _ = False
weaponFruit : Fruit -> Bool
weaponFruit Apple = True
weaponFruit Orange = True
weaponFruit Lemon = True
weaponFruit _ = False
Вы можете определить свои исходные предикаты как вызовы псевдонимов типов Is
с соответствующей функцией принятия решения:
WineStock : Fruit -> Type
WineStock = Is wineFruit
И, конечно же, isnt
позволяет отклонить невозможные случаи:
dismiss : WineStock Orange -> Void
dismiss = isnt