【发布时间】:2019-07-12 04:39:05
【问题描述】:
我正在尝试解决与"Haskell Programming from First Principles" 第 15 章中的this other question 相同的练习。我已经创建了一个 Semigroup 实例,但在编写练习的 QuickCheck 部分时遇到了问题。
一个 Semigroup 实例应该满足:
a <> (b <> c) == (a <> b) <> c
其中<> 是半群映射。
我想出了以下几点:
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 包裹的函数),但练习文本表明这样的事情是可能的。
关于如何完成这项工作的任何想法?
编辑:
作者对此练习给出了提示:
提示:此函数最终将应用于单个值 a 型。但是你会有多个函数可以产生一个 b 类型的值。我们如何组合多个值,所以我们有 一个b?这可能会很棘手!请记住, Combine 内部值的类型是函数的类型。如果你 无法弄清楚 CoArbitrary,不用担心 QuickChecking 这个。
@Li-yao Xia 的答案似乎是最好的答案。但是我不应该使用这个 CoArbitrary 实例吗?
【问题讨论】:
-
最新版本的 QC 支持 functions,但您必须更改类型 -
newtype Combine' fun a b = Combine (fun a b); type Combine = Combine' (->); type Combine_Test = Combine' Fun(或创建一个复制结构的不同类型,但将->替换为Fun) -
虽然在这个例子中他们希望你在整体上使用
quickCheck,但使用 lambda 演算减少函数通常可以证明相等。
标签: haskell types typeclass quickcheck