[英]Scala type class to extend generic type: No implicits found for parameter
我想編寫一個類型類,為通用類型添加一些行為。 但是,我不知道該怎么做。 我不斷遇到以下錯誤。
假設您有一個通用類型MyList[A]
:
trait MyList[A]
object MyList {
case class Empty[A]() extends MyList[A]
case class Node[A](value: A, next: MyList[A]) extends MyList[A]
}
現在,您要向此類添加一些行為,例如,將其轉換為Stream[A]
。 基於類型類的擴展似乎很合適:
// inspired by https://scalac.io/typeclasses-in-scala
trait MyListExt[T, A <: MyList[T]] {
def stream(a: A): Stream[T]
}
object MyListExt {
def apply[T, A <: MyList[T]](implicit a: MyListExt[T, A]): MyListExt[T, A] = a
object ops {
implicit class MyListExtOps[T, A <: MyList[T]](val a: A) extends AnyVal {
def stream(implicit ext: MyListExt[T, A]): Stream[T] = ext.stream(a)
}
}
private type T0
implicit val myListToStreamImpl: MyListExt[T0, MyList[T0]] = new MyListExt[T0, MyList[T0]] {
override def stream(a: MyList[T0]): Stream[T0] = {
def fold[T1](l: MyList[T1], acc: Stream[T1]): Stream[T1] = l match {
case MyList.Empty() => acc
case MyList.Node(value, next) => fold(next, acc :+ value)
}
fold(a, Stream.empty)
}
}
}
現在,當我嘗試在代碼中使用此類型類時,在l.stream
出現以下錯誤:
No implicits found for parameter ext: MyListExt[T_, MyList[Int]]
object MyListTest {
def main(args: Array[String]): Unit = {
import MyListExt.ops._
val l: MyList[Int] = MyList.Node(1, MyList.Node(2, MyList.Node(3, MyList.Empty())))
l.stream.foreach(println)
}
}
我在做什么錯,或者我怎樣才能使l.stream
正常工作?
我已經看到許多涉及類型類和隱式轉換的示例,但到目前為止,還沒有一個對泛型類型進行操作。
implicit def myListToStreamImpl[T]: MyListExt[T, MyList[T]] = new MyListExt[T, MyList[T]] {
override def stream(a: MyList[T]): Stream[T] = {
def fold(l: MyList[T1], acc: Stream[T1]): Stream[T1] = l match {
case MyList.Empty() => acc
case MyList.Node(value, next) => fold(next, acc :+ value)
}
fold(a, Stream.empty[T1])
}
}
您的類型不一致,因為您出於某種奇怪的原因而使用了該private type
。 嵌套在對象內部的類型具有完全不同的應用程序,它們與您當前的用例無關。
問題在於,在l.stream.foreach(println)
, l
被隱式轉換為new MyListExt.ops.MyListExtOps[.., ..](l)
,泛型被推斷為[Nothing, MyList[Int]]
,不滿足[T, A <: MyList[T]]
。
我看不到同時用T
和A <: MyList[T]
MyListExt
A <: MyList[T]
參數化MyListExt
理由。 我想T
就足夠了,請使用MyList[T]
而不是A
不要使用private type T0
,只需將T0
aka T
myListToStreamImpl
(使其為def
)。
嘗試
trait MyList[A]
object MyList {
case class Empty[A]() extends MyList[A]
case class Node[A](value: A, next: MyList[A]) extends MyList[A]
}
trait MyListExt[T] {
def stream(a: MyList[T]): Stream[T]
}
object MyListExt {
def apply[T](implicit a: MyListExt[T]): MyListExt[T] = a
object ops {
implicit class MyListExtOps[T](val a: MyList[T]) extends AnyVal {
def stream(implicit ext: MyListExt[T]): Stream[T] = ext.stream(a)
}
}
implicit def myListToStreamImpl[T]: MyListExt[T] = new MyListExt[T] {
override def stream(a: MyList[T]): Stream[T] = {
def fold[T1](l: MyList[T1], acc: Stream[T1]): Stream[T1] = l match {
case MyList.Empty() => acc
case MyList.Node(value, next) => fold(next, acc :+ value)
}
fold(a, Stream.empty)
}
}
}
object MyListTest {
def main(args: Array[String]): Unit = {
import MyListExt.ops._
val l: MyList[Int] = MyList.Node(1, MyList.Node(2, MyList.Node(3, MyList.Empty())))
l.stream.foreach(println)
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.