具体的には、Semigroup と「Semigroup である」Sum タイプを定義し、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>
より一般的な、または少なくとも aのArbitrary
インスタンスを作成する方法と、型whereの x、y、および z を取ることができるより一般的なものを作成する方法について、具体的な型であることに迷っています。Sum[Numeric]
Gen[Sum[Numeric]]
semigroupAssocProp
S
S extends Semigroup[T]
T
Scala で書いた Haskell のバージョンに機能をできる限り近づけようとしています。