Ответ 1
Такого рода рассуждения действительно возможны, используя неинтерпретированные сорта и функции. Однако следует предупредить, что рассуждение о таких структурах обычно требует количественных аксиом, а SMT-решатели обычно не очень хорошо разбираются в квантификаторах.
Сказав это, вот как я буду это делать, используя SBV.
Во-первых, некоторый код котельной пластины, чтобы получить неинтерпретированный тип T
:
{-# LANGUAGE DeriveDataTypeable #-}
import Data.Generics
import Data.SBV
-- Uninterpreted type T
data T = TBase () deriving (Eq, Ord, Data, Typeable, Read, Show)
instance SymWord T
instance HasKind T
type ST = SBV T
Как только вы сделаете это, вы получите доступ к неинтерпретированному типу T
и его символическому аналогу ST
. Пусть объявить plus
и zero
, снова просто неинтерпретированные константы с правильными типами:
-- Uninterpreted addition
plus :: ST -> ST -> ST
plus = uninterpret "plus"
-- Uninterpreted zero
zero :: ST
zero = uninterpret "zero"
До сих пор мы сообщали SBV, что существует тип T
, а также функция plus
и константа zero
; прямо не интерпретируясь. То есть, решатель SMT не делает никаких предположений, кроме того, что они имеют заданные типы.
Сначала попытаемся доказать, что 0+x = x
:
bad = prove $ \x -> zero `plus` x .== x
Если вы попробуете это, вы получите следующий ответ:
*Main> bad
Falsifiable. Counter-example:
s0 = T!val!0 :: T
Что говорит вам решатель SMT, так это то, что свойство не выполняется, и здесь значение, в котором оно не выполняется. Значение T!val!0
является специфическим ответом Z3
; другие решатели могут возвращать другие вещи. Это, по сути, внутренний идентификатор для жителя типа T
; и кроме этого мы ничего не знаем об этом. Конечно, это не очень полезно, так как вы действительно не знаете, какие ассоциации он сделал для plus
и zero
, но этого можно ожидать.
Чтобы доказать свойство, скажем SMT решателю еще две вещи. Во-первых, что plus
является коммутативным. А во-вторых, что zero
, добавленный справа, ничего не делает. Они выполняются с помощью вызовов addAxiom
. К сожалению, вы должны написать свои аксиомы в синтаксисе SMTLib, так как SBV не поддерживает (по крайней мере пока) поддержку аксиом, написанных с использованием Haskell. Также обратите внимание на использование монады Symbolic
здесь:
good = prove $ do
addAxiom "plus-zero-axioms"
[ "(assert (forall ((x T) (y T)) (= (plus x y) (plus y x))))"
, "(assert (forall ((x T)) (= (plus x zero) x)))"
]
x <- free "x"
return $ zero `plus` x .== x
Обратите внимание, как мы сказали решателю x+y = y+x
и x+0 = x
, и попросили его доказать 0+x = x
. Написание аксиом таким образом выглядит очень уродливо, так как вам нужно использовать синтаксис SMTLib, но это текущее состояние дел. Теперь мы имеем:
*Main> good
Q.E.D.
Количественные аксиомы и неинтерпретированные типы/функции - это не самые простые вещи, которые можно использовать через интерфейс SBV, но вы можете получить некоторый пробег из этого пути. Если вы сильно используете квантификаторы в своих аксиомах, маловероятно, что решатель сможет ответить на ваши запросы; и, скорее всего, ответит unknown
. Все зависит от решателя, который вы используете, и насколько сложно доказать свойства.