I'm specifically trying to define Semigroup and a Sum type which 'is a' Semigroup and check the Associative property of Semigroup generically using ScalaCheck.
I first wrote this out in Haskell because I find it easier to think of these things first in Haskell syntax and then translate them to Scala.
So in Haskell, I wrote the following which works in 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)
I'm trying to create something roughly equivalent in Scala. So far, I have what you see below:
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>
I'm lost on how to create an Arbitrary
instance for a more generic Sum[Numeric]
, or at least a Gen[Sum[Numeric]]
and how to create a more generic semigroupAssocProp
that could take an x, y, and z of type S
where S extends Semigroup[T]
, with T
being any concrete type.
I'm really trying to get as close in functionality to the Haskell version I wrote as possible in Scala.