Рассмотрим следующее определение категории:
trait Category[~>[_, _]] {
def id[A]: A ~> A
def compose[A, B, C](f: A ~> B)(g: B ~> C): A ~> C
}
Здесь экземпляр для унарных функций:
object Category {
implicit def fCat = new Category[Function1] {
def id[A] = identity
def compose[A, B, C](f: A => B)(g: B => C) = g.compose(f)
}
}
Теперь категории подчиняются некоторым законам. Относительная композиция (.
) и тождество (id
):
forall f: categoryArrow -> id . f == f . id == f
Я хочу протестировать это с помощью ScalaCheck. Пусть попробуйте функции над целыми числами:
"Categories" should {
import Category._
val intG = { (_ : Int) - 5 }
"left identity" ! check {
forAll { (a: Int) => fCat.compose(fCat.id[Int])(intG)(a) == intG(a) }
}
"right identity" ! check {
forAll { (a: Int) => fCat.compose(intG)(fCat.id)(a) == intG(a) }
}
}
Но они определяются количественно по (i) конкретному типу (Int
) и (ii) определенной функции (intG
). Итак, вот мой вопрос: как далеко я могу пойти в плане обобщения вышеуказанных тестов и как? Или, другими словами, можно ли создать генератор произвольных функций A => B
и предоставить их ScalaCheck?