Haskell 越界`select`即使我`constraint`索引
我有一个值的静态长度列表Haskell 越界`select`即使我`constraint`索引,haskell,smt,sbv,symbolic-execution,Haskell,Smt,Sbv,Symbolic Execution,我有一个值的静态长度列表ks::[SInt16]和一个索引x::SInt16。我想使用x索引到列表中: (.!) :: (Mergeable a) => [a] -> SInt16 -> a xs .! i = select xs (error "(.!) : out of bounds") i 我希望能够将(.!)与足够约束的x一起使用,如下所示: sat $ do let ks = [1, 3, 5, 2, 4] x &l
ks::[SInt16]
和一个索引x::SInt16
。我想使用x
索引到列表中:
(.!) :: (Mergeable a) => [a] -> SInt16 -> a
xs .! i = select xs (error "(.!) : out of bounds") i
我希望能够将(.!)
与足够约束的x
一起使用,如下所示:
sat $ do
let ks = [1, 3, 5, 2, 4]
x <- sInt16 "x"
constrain $ 0 .<= x .&& x .< literal (fromIntegral $ length ks)
let y = ks .! x
return $ y .< x
sat$do
设ks=[1,3,5,2,4]
x简单解
select
在符号执行期间由SBV完全展开,因此您必须提供适当的默认值,正如您所发现的那样。因此,如果您确实想使用选择,您必须在那里找到一个实际值
为了满足您的迫切需要,我建议您只需定义:
(.!):(可合并a)=>[a]->SInt16->a
[] .! _ = 错误“(.!):空列表!”
(x:)!。!i=选择xs x i
只要您确保在i
上声明了足够的约束,这应该可以正常工作
稍微好一点的方法
以上要求用户跟踪索引变量的适当约束,这可能会变得相当棘手。在这些情况下使用的一个简单技巧是使用“智能”构造函数。首先定义:
import Data.SBV
mkIndex::SIntegral b=>String->[a]->Symbolic(SBV b)
MKDINDEX nm lst=我是否在16->a
[] .! _ = 错误“(.!):空列表!”
(x:)!。!i=选择xs x i
现在你可以说:
p=sat$do让ks=[1,3,5,2,4]
x字符串->符号(索引a b)
mkIndex nm=do def索引a b->SBV a
xs。!索引(i,i')=选择xsi'
现在假设您尝试执行sat
,但在索引上设置了不正确的约束:
p=sat$do让ks=[1,3,5,2,4]
xi@(Index(x))::Index Int16 Int16 10
让y=ks。!席
纯$y。
您将获得:
*Main> p
Satisfiable. Model:
x_access_out_of_bounds_value = 0 :: Int16
x = 16386 :: Int16
通过这种方式,您可以看到出现了问题,以及解算器选择了什么值来满足访问超出边界的情况
总结
你采取哪种方法取决于你的实际需要。但如果可能的话,我建议至少使用第二种方法,因为SMT解算器总是可以“聪明地”选择值,从而为您提供意外的模型。这样至少可以防止最明显的bug。在生产系统中,我坚持使用第三种方法,因为调试由复杂约束引起的bug在实践中可能相当困难。你留给自己的“跟踪”变量越多越好