Python z3中的GADT出现意外行为,获取的值等于每个整数
这将是一个正确的问题,有人更深入地了解z3或在其怪癖的兴趣 大家好,我正在运行以下测试,以了解GADT如何在z3 python中工作。看起来unfoobarfoob的值等于任何整数?是这样吗 下面是一个有效的测试-你能解释一下为什么它有效吗Python z3中的GADT出现意外行为,获取的值等于每个整数,python,z3,z3py,Python,Z3,Z3py,这将是一个正确的问题,有人更深入地了解z3或在其怪癖的兴趣 大家好,我正在运行以下测试,以了解GADT如何在z3 python中工作。看起来unfoobarfoob的值等于任何整数?是这样吗 下面是一个有效的测试-你能解释一下为什么它有效吗 import pytest from z3 import Datatype, Solver, IntSort, Int def test_stackoverflow(): FooBar = Datatype('FooBar') FooBar
import pytest
from z3 import Datatype, Solver, IntSort, Int
def test_stackoverflow():
FooBar = Datatype('FooBar')
FooBar.declare('foo', ('unfoo', IntSort()))
FooBar.declare('bar', ('unbar', FooBar))
FooBar = FooBar.create()
foo = FooBar.foo
unfoo = FooBar.unfoo
bar = FooBar.bar
unbar = FooBar.unbar
solver = Solver()
solver.push()
a = Int('a')
b = Int('b')
solver.add(a == unfoo(bar(foo(b))))
assert str(solver.check()) == "sat"
model = solver.model()
assert model.evaluate(a).as_long() == 1
assert model.evaluate(b).as_long() == 0
solver.pop()
这确实令人困惑,但我认为z3做的是正确的 如果我们转储生成的SMT库,就更容易看到发生了什么。在调用check之前添加print solver.sepxr。我得到: 这需要一点凝视,但以下是涉及的类型: b是整数 foob是一个FooBar,但它特别具有构造函数foo。 bar foob是一个FooBar,但它特别具有构造函数bar。 unfoo-bar-foob是一个Int,但它将unfoo选择器应用于使用bar构造的对象。 这就是问题所在:你用其他东西构建的东西破坏了一个术语 对于这种情况,典型的“SMTLib”答案没有明确说明。也就是说,逻辑不保证什么是有效的,因此允许解算器以它想要的任何方式实例化。所以,你得到的模型是正确的;虽然有点困惑 为了更好地了解这一点,想象一下您将如何用Haskell这样的语言编写代码: 数据FooBar=Foo{unfoo::Int}| Bar{unbar::FooBar} 检查a b=a==unfoo Bar Foo b 让我们试试:ghci是Haskell解释器:
ghci> check 1 0
*** Exception: No match in record selector unfoo
啊!!它告诉我们我们搞砸了。我们能修好它吗?我们开始:
数据FooBar=Foo Int | Bar{unbar::FooBar}
unfoo::FooBar->Int
unfoo Foo i=i
unfoo Bar=1-在此处方便地选择结果!
检查a b=a==unfoo Bar Foo b
我们得到:
ghci> check 1 0
True
瞧!请注意,我是如何定义unfoo的,以使其令人满意
本质上,z3做了同样的事情。由于应用于使用bar构造的对象的unfoo析构函数未指定,因此它只选择一个使问题可满足的解释。总而言之,当您定义unfoo之类的析构函数时,您要说的是:
如果你收到一个foo值,那么告诉我里面是什么
如果你收到一个非foo值,那么给我你想要的;只要它的类型正确并且满足我的其他约束条件。
而这正是Z3为你所做的。我希望这是清楚的。不过这是个很酷的例子
ghci> check 1 0
True