我試圖解決與"Haskell Programming from First Principles"第15章中的this other question相同的練習。我已經創建了一個Semigroup實例,並且在編寫練習的QuickCheck部分時遇到了麻煩。如何測試此數據類型的半羣法則?
半羣實例應該滿足:
a <> (b <> c) == (a <> b) <> c
<>
哪裏是半羣mappend。
我想出了以下內容:
import Data.Semigroup
import Test.QuickCheck
semigroupAssoc :: (Eq m, Semigroup m) => m -> m -> m -> Bool
semigroupAssoc a b c = (a <> (b <> c)) == ((a <> b) <> c)
newtype Combine a b = Combine { unCombine :: (a -> b) }
instance Semigroup b => Semigroup (Combine a b) where
(Combine f) <> (Combine g) = Combine (\x -> (f x) <> (g x))
instance CoArbitrary (Combine a b) where
coarbitrary (Combine f) = variant 0
instance (CoArbitrary a, Arbitrary b) => Arbitrary (Combine a b) where
arbitrary = do
f <- arbitrary
return $ Combine f
type CombineAssoc a b = Combine a b -> Combine a b -> Combine a b -> Bool
main :: IO()
main = do
quickCheck (semigroupAssoc :: CombineAssoc Int Bool)
一切編譯除了quickCheck
線,在那裏抱怨說有No instance for (Eq (Combine Int Bool)) arising from a use of ‘semigroupAssoc’
。
我不認爲有一種方法可以測試兩個任意函數是否相等(包含Combine
的函數),但練習文本表明這樣的事情是可能的。
關於如何使這項工作的任何想法?
編輯:
作者給出一個提示本練習:
提示:此功能最終將應用於單值類型的 。但是,您將擁有多個可以生成類型b的 值的函數。我們如何組合多個值,所以我們有 單個b?這一個可能會很棘手!請記住,組合內的值的 類型是函數的值。如果你 找不到CoArbitrary,不要擔心這個問題QuickChecking 。
@李霞瑤的回答似乎是最好的答案。但是,我不應該使用這個CoArbitrary實例來做什麼嗎?
最新的QC支持版本[功能](https://hackage.haskell.org/package/QuickCheck-2.9.2/docs/Test-QuickCheck-Function.html),但你必須改變你的type - 'newtype Combine'fun ab = Combine(fun ab);鍵入Combine = Combine'( - >);類型Combine_Test = Combine'Fun'(或創建一個複製結構的獨特類型,但用'Fun'替換' - >') – user2407038
雖然對於這個例子他們希望你總體上使用'quickCheck',使用lambda演算可以減少函數一般證明平等。 –