我的情况是我有像
这样的数据类型data X = X {foo :: SInteger, bar :: SInteger}
我希望证明这一点。
forAll_ $ \x -> foo x + bar x .== bar x + foo x
使用haskell的sbv。
这不会编译,因为X -> SBool
不是Provable的实例。我可以用例如
instance (Provable p) => Provable (X -> p) where
forAll_ k = forAll_ $ \foo bar -> forAll_ $ k $ X foo bar
forAll (s : ss) k =
forAll ["foo " ++ s, "bar " ++ s] $ \foo bar -> forAll ss $ k $ X foo bar
forAll [] k = forAll_ k
-- and similarly `forSome_` and `forSome`
但这很乏味且容易出错(例如,当forSome
应该被使用时使用forAll
。有没有办法自动为我的类型派生Provable
?
答案 0 :(得分:2)
至少可以减少错误:
onX :: (((SInteger, SInteger) -> a) -> b) -> ((X -> a) -> b)
onX f g = f (g . uncurry X)
instance Provable p => Provable (X -> p) where
forAll_ = onX forAll_
forSome_ = onX forSome_
forAll = onX . forAll
forSome = onX . forSome
如果SBV现有的多达7元组的实例不足够,那么这也是一种可推广的模式。
data Y = Y {a, b, c, d, e, f, g, h, i, j :: SInteger}
-- don't try to write the types of these, you will wear out your keyboard
fmap10 = fmap . fmap . fmap . fmap . fmap . fmap . fmap . fmap . fmap . fmap
onY f g = f (fmap10 g Y)
instance Provable p => Provable (Y -> p) where
forAll_ = onY forAll_
forSome_ = onY forSome_
forAll = onY . forAll
forSome = onY . forSome
但仍然很乏味。
答案 1 :(得分:0)
如果你真的想直接在你的lambda表达式中使用量词,那么Daniel的回答是“尽可能好”。但是,我强烈建议您为您的类型定义Provable
的变体,而不是创建free
个实例:
freeX :: Symbolic X
freeX = do f <- free_
b <- free_
return $ X f b
现在您可以像这样使用它:
test = prove $ do x <- freeX
return $ foo x + bar x .== bar x + foo x
这更容易使用,并且很好地适应了约束。例如,如果您的数据类型具有额外约束,即两个组件都是正数,并且第一个组件大于第二个组件,那么您可以这样写freeX
:
freeX :: Symbolic X
freeX = do f <- free_
b <- free_
constrain $ f .> b
constrain $ b .> 0
return $ X f b
请注意,这可以在prove
和sat
上下文中正常运行,因为free
知道在每种情况下如何正确行事。
我认为这更易读,更易于使用,即使它会强制您使用该功能。您还可以创建一个接受名称的版本,如下所示:
freeX :: String -> Symbolic X
freeX nm = do f <- free $ nm ++ "_foo"
b <- free $ nm ++ "_bar"
constrain $ f .> b
constrain $ b .> 0
return $ X f b
test = prove $ do x <- freeX "x"
return $ foo x + bar x .== bar x * foo x
现在我们得到:
*Main> test
Falsifiable. Counter-example:
x_foo = 3 :: Integer
x_bar = 1 :: Integer
您还可以通过SBV使X
“可解析”。在这种情况下,完整代码如下所示:
data X = X {foo :: SInteger, bar :: SInteger} deriving Show
freeX :: Symbolic X
freeX = do f <- free_
b <- free_
return $ X f b
instance SatModel X where
parseCWs xs = do (x, ys) <- parseCWs xs
(y, zs) <- parseCWs ys
return $ (X (literal x) (literal y), zs)
以下测试表明:
test :: IO (Maybe X)
test = extractModel `fmap` (prove $ do
x <- freeX
return $ foo x + bar x .== bar x * foo x)
我们有:
*Main> test >>= print
Just (X {foo = -4 :: SInteger, bar = -5 :: SInteger})
现在,您可以按照自己的意愿拍摄反例并进行后期处理。