使用Haskell的Quickcheck来检查传递性

时间:2018-06-17 11:20:54

标签: haskell testing

如何让Quickcheck检查下面代码中的传递属性?代码表示一堆物理块。块只能使用操作MoveOnto bl b2 s放置在空表或另一个块上,操作b2被移动到堆栈或表bl上的s中。我的Quickcheck尝试只是挂起并且没有产生任何结果。

import Test.QuickCheck
data Block = Block Int deriving (Show,Eq)
data Stack = EmptyTable  |  MoveOnto Block Block Stack deriving  (Show,Eq) 
isOn :: Block -> Block -> Stack -> Bool
isOn b1 b2 (MoveOnto b3 b4 s) |  ((b1 == b3) && (b4 == b2)) || (isOn b4 b2 s)   =  True
isOn _ _ _  = False

b1' = Block 1
b2' = Block 2
b3' = Block 3
b4' = Block 4
b5' = Block 5
b6' = Block 6
b7' = Block 7
b8' = Block 8

-- Hand made test
testTransitivityTrue b1 b2 b3 b4 b5  = isOn b1 b5 (MoveOnto b1 b2 (MoveOnto b2 b3 (MoveOnto b3 b4 (MoveOnto b4 b5 EmptyTable))))

instance Arbitrary (Block) where
  arbitrary =  arbitrary


instance Arbitrary (Stack) where
  arbitrary = oneof [return EmptyTable, MoveOnto <$> arbitrary <*> arbitrary <*> arbitrary]

prop_pass b1 b2 s   = isOn b1 b2 (MoveOnto b1 b2 s)

1 个答案:

答案 0 :(得分:4)

它挂起,因为在尝试构造任意Block时,您执行无限递归。事实上:

instance Arbitrary (Block) where
  arbitrary = arbitrary

所以这就意味着你写了一个可以通过生成任意块来生成任意块。这当然行不通。您可以定义任意Int,然后使用以下内容构造一个块:

instance Arbitrary (Block) where
  arbitrary = fmap Block arbitrary

现在可以构造任意块,也可以构造任意堆栈,尽管如果我们将概率建模为统一的话,严格意义上也可能会运行无限时间(由于技术原因) ,我们知道堆栈建设最终会停止。