是否有可能构造一个更高阶函数isAssociative
,它接受两个参数的另一个函数并确定该函数是否是关联的?
类似的问题,但对于其他属性,如交换性。
如果这是不可能的,有没有办法以任何语言自动化它?如果有我感兴趣的Agda,Coq或Prolog解决方案。
我可以设想一个强力解决方案,它可以检查每个可能的参数组合,永远不会终止。但在这种情况下,“永不终止”是一种不受欢迎的财产。
答案 0 :(得分:9)
我想到的第一个解决方案是使用QuickCheck。
quickCheck $ \(x, y, z) -> f x (f y z) == f (f x y) z
quickCheck $ \(x, y) -> f x y == f y x
其中f
是我们正在测试的函数。它不会证明既没有联系也没有交换;这是编写你一直在思考的强力解决方案的最简单方法。 QuickCheck的优势在于它能够选择测试的参数,这有望成为测试代码的极端情况。
您要求的isAssociative
可以定义为
isAssociative
:: (Arbitrary t, Show t, Eq t) => (t -> t -> t) -> IO ()
isAssociative f = quickCheck $ \(x, y, z) -> f x (f y z) == f (f x y) z
它位于IO
,因为QuickCheck随机选择测试用例。
答案 1 :(得分:3)
我猜Haskell并不适合这类事情。通常你完全相反检查。您声明您的对象具有某些属性,因此可以以某种特殊方式使用(请参阅Data.Foldable)。有时您可能想要推广您的系统:
import Control.Parallel
import Data.Monoid
pmconcat :: Monoid a => [a] -> a
pmconcat [x] = x
pmconcat xs = pmconcat (pairs xs) where
pairs [] = []
pairs [x] = [x]
pairs (x0 : x1 : xs') = y `par` (y : ys) where
y = x0 `mappend` x1
ys = pairs xs'
data SomeType
associativeSlowFold = undefined :: SomeType -> SomeType -> SomeType
data SlowFold = SlowFoldId
| SlowFold { getSlowFold :: SomeType }
instance Monoid SlowFold where
mempty = SlowFoldId
SlowFoldId `mappend` x = x
x `mappend` SlowFoldId = x
x0 `mappend` x1 = SlowFold y where
y = (getSlowFold x0) `associativeSlowFold` (getSlowFold x1)
mconcat = pmconcat
如果您真的想要证明系统,您可能还想查看您提到的那些证明助理。 Prolog - 是逻辑语言,我不认为它也非常适合。但它可能会被用来写一些简单的助手。即应用关联性规则,看到在较低层次上,不可能得出平等。