Я перевожу код на Haskell в https://sebfisch.github.io/haskell-regexp/regexp-play.pdf в Scala для самостоятельного изучения.
Я перевел «класс полукольца» (стр. 2) таким образом:
trait Semiring[S] {
def zero: S
def one: S
def add(a: S, b: S): S
def mult(a: S, b: S): S
}
и соответствующий класс SemiringI (стр. 7) следующим образом:
trait SemiringI[S] extends Semiring[S] {
def index: Int => S
}
Затем я должен был предоставить экземпляры для определенных параметров типа, поэтому я попытался действовать, как мне кажется, каноническим способом, то есть определить их как неявные значения.
implicit val semiringLeftmost = new Semiring[LeftmostT] {
// ...implementation of zero, one, add, mult...
}
Однако у меня были некоторые проблемы, когда мне приходилось определять экземпляр SemiringI для LeftmostT:
implicit val semiringILeftmost = new SemiringI[LeftmostT] {
// ...implementation of zero, one, add, mult (same as for Semiring[LeftmostT])
// ...implementation of index
}
Мне показалось, что мне пришлось повторить реализации функций, уже определенных в Semiring [LeftmostT], которые, конечно, не были бы масштабируемыми.
Я искал в Интернете ответы, но не смог их найти.
Например, в https://www.slideshare.net/jdegoes/scalaz-8-a-whole-new-game (слайд 7) MonoidInt не использует определение append из полугруппы, как я ожидал.
В конце концов мне удалось найти способ продолжить, а именно:
// traits Semiring[S] and SemiringI[S] defined as above
class semiringLeftmostC extends Semiring[LeftmostT] {
// ...implementation of zero, one, add, mult...
}
implicit val semiringLeftmost = new semiringLeftmostC()
class semiringILeftmostC extends semiringLeftmostC with SemiringI[LeftmostT] {
// ...implementation of index
}
implicit val semiringILeftmost = new semiringILeftmostC()
но я не уверен, что это лучший.
Может кто-нибудь объяснить мне, есть ли другие возможности для достижения тех же целей, то есть повторное использование кода в иерархиях экземпляров классов типов?
Заранее спасибо.