我特别想定义 Semigroup 和 Sum 类型,它是一个 Semigroup,并使用 ScalaCheck 通常检查 Semigroup 的 Associative 属性。
我首先在 Haskell 中写了这个,因为我发现首先在 Haskell 语法中考虑这些东西然后将它们转换为 Scala 更容易。
所以在 Haskell 中,我写了以下在 GHCi 中有效的代码:
newtype Sum a = Sum a deriving (Show, Eq)
instance Num a => Num (Sum a) where
(+) (Sum x) (Sum y) = Sum (x + y)
class Semigroup a where
(<>) :: a -> a -> a
instance Num a => Semigroup (Sum a) where
(<>) = (+)
instance Arbitrary a => Arbitrary (Sum a) where
arbitrary = fmap Sum arbitrary
semigroupAssocProp x y z = (x <> (y <> z)) == ((x <> y) <> z)
quickCheck (semigroupAssocProp :: Num a => Sum a -> Sum a -> Sum a -> Bool)
我正在尝试在 Scala 中创建大致等效的东西。到目前为止,我有你在下面看到的:
trait Semigroup[A] {
def |+|(b: A): A
}
case class Sum[A: Numeric](n: A) extends Semigroup[Sum[A]] {
def |+|(x: Sum[A]): Sum[A] = Sum[A](implicitly[Numeric[A]].plus(n, x.n)
}
val semigroupAssocProp = Prop.forAll { (x: Sum[Int], y: Sum[Int], z: Sum[Int]) =>
(x |+| (y |+| z)) == ((x |+| y) |+| z)
}
val chooseSum = for { n <- Gen.chooseNum(-10000, 10000) } yield Sum(n)
// => val chooseSum Gen[Sum[Int]] = org.scalacheck.Gen$$anon$<some hash>
我不知道如何Arbitrary
为更通用Sum[Numeric]
的 或至少 a创建一个实例,Gen[Sum[Numeric]]
以及如何创建一个更通用的可以采用wheresemigroupAssocProp
类型的 x、y 和 z并且是任何具体类型的实例。S
S extends Semigroup[T]
T
我真的想在功能上尽可能接近我在 Scala 中编写的 Haskell 版本。