我一直在關注這篇博文,試圖了解如何在Scala 3中使用路徑依賴型別來模擬存在量化的型別:https://dev.to/raquo/existential-crisis-implementing-mapk-in-scala-3-2fo1
然后我做了下面這個例子。
首先我們定義單體:
trait Monoid[A]。
val id: A
def combine(l: A, r: A)。A: A.
object StringMonoid extends Monoid[String]。
val id = "".
def combine(l: String, r: String) = l r
object AdditiveIntMonoid extends Monoid[Int]。
val id = 0.
def combine(l: Int, r: Int) = l r
object MultiplicativeIntMonoid extends Monoid[Int]。
val id = 1.
def combine(l: Int, r: Int) = r * r
現在,假設我想寫的代碼可以接受一組單體,這些單體可能并不都具有相同的底層型別。 比如說
def ids(ms: Monoid*) = // This won't compile because Monoid with no argument 。
for { m <- ms } yield m.id //不是一個型別。
或者
def asList(pair: ((E, Monoid[E]) for any E)*) = // This is also not valid scala
pairs.toList
通過一些作業,我可以按照博客中的模式實作我想要的行為。
首先定義一個具有路徑依賴性的內部型別來模擬forSome:
type any[F[_] ] = {
type Member;
type Ops = F[Member]
}
還有幾個名字不好聽的隱式轉換,幫助我制作相關型別的實體:
given any_algebra[F[_], A] 。Conversion[F[A], any[F]#Ops] = _. asInstanceOf[any[F]#Ops]
鑒于any_algebra_with_member[F[_], A] 。Conversion[(A, F[A])。) (any[F]#Member, any[F]#Ops) ] =
_.asInstanceOf[(any[F]#Member, any[F]#Ops) ]
現在我可以寫
了def ids(ms: List[any[Monoid]#Ops] =
for { m <- ms } yield m.id
def all[F[_]](fs: any[F]#Ops*) = fs. toList
val ms = all(StringMonoid, MultiplicativeIntMonoid, AdditiveIntMonoid, StringMonoid)
val units = ids(all(AdditiveIntMonoid, StringMonoid, MultiplicativeIntMonoid)
def many[F[_]](對。(any[F]#Member, any[F]#Ops)*) = pairs. toList
val mms = many(
7 -> AdditiveIntMonoid,
3 -> MultiplicativeIntMonoid,
"foo" -> StringMonoid,
"bar" -> StringMonoid, "bar".
)
而且都能作業。 我不能寫
val ms = all(StringMonoid, "hello", AdditiveIntMonoid, StringMonoid)
因為"hello"不是一個Monoid,或者
val mms = many(
"foo" -> StringMonoid,
3 -> StringMonoid, StringMonoid.
)
因為3不是一個字串。
我的問題是,為什么最后這部分能如我所愿。 為什么不能我寫many(3 -> StringMonoid)? 在def many[F[_]](pair: (any[F]#Member, any[F]#Ops)*)中,是什么約束了any[F]在元組型別中的兩次出現都是指同一型別? 我應該從哪里(Scala語言規范或其他地方)開始閱讀,以便能夠從第一原理上理解這個問題?
uj5u.com熱心網友回復:
這是因為你有這個隱含的轉換
Conversion[(A, F[A])。) (any[F]#Member, any[F]#Ops) ]
many接受(any[F]#Member, any[F]#Ops)的元組。因此,當你提供元組"foo" -> StringMonoid時,編譯器使用該隱式轉換將其轉換為所請求的型別的元組。但是這種轉換只對符合(A, F[A])形狀的元組有效。也就是說,兩個成員中的A必須是同一型別。但是當你提供3 -> StringMonoid時,左邊的A是Int,右邊的A是String,所以隱式轉換將不起作用。
編譯器可能仍然試圖通過推斷A = Any來使其作業,但是Monoid[String]不是Monoid[Any]的子型別,因為它是不變數。所以這也是行不通的。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/326148.html
標籤:
上一篇:scala中的日期時間格式化錯誤。"在索引0處無法決議文本"
下一篇:谷歌地圖在頁面導航時顯示部分地圖
