This is a suite of questions discussed on discord, but I’m moving it here to better document the discussion. I have an abstract class Magma
which I’d like to refactor to remove the dependency on LazyList
, thus allowing a larger set of generated collections. I’m omitting a few things from the class definition, which I hope are not important.
abstract class Magma[T] {
import HeavyBool._
def gen(): LazyList[T] // a generator of objects of the Magma
def isClosed(): HeavyBool = {
forallM("a", gen()){ a:T =>
forallM("b", gen()) { b: T =>
member(op(a, b)) ++ Map("op(a,b)" -> op(a, b))
}}}.annotate("closed")
}
With the help of balmungsan3 (thanks BalmungSan (Luis Miguel Mejia)) I refactored it to this.
import cats.Foldable
abstract class Magma[T] {
import HeavyBool._
def gen[C[_]:Foldable]()(implicit ev:Foldable[C]): C[T]
def isClosed(): HeavyBool = {
forallM("a", gen()){ a:T =>
forallM("b", gen()) { b: T =>
member(op(a, b)) ++ Map("op(a,b)" -> op(a, b))
}}}.annotate("closed")
...
}
Now, I don’t know how to refactor the subclasses. How should I override gen
in subclasses, 1) when I still want to be collection agnostic, and 2) when I want to specify a particular collection such as LazyList[Int]
?
abstract class ModP(p: Int) extends Magma[Int] {
override def toString: String = s"ModP($p)"
override def gen()(implicit ev: Foldable[LazyList[_]]): LazyList[Int] = Magma.genFinite(p - 1)
...
}
class AdditionModP(p: Int) extends ModP(p) {
...
}
I get several errors I don’t understand.
First, how do I write methods in Magma
class which make calls to gen
?
Next, how can I specify an implementation for gen
to have a specific type in a subclass ModP
of Magma
?
Third, how can I create a subclass of ModP
where I don’t override gen
?