英文:
Scala 3. Defining extension for class + all subclasses
问题
学习 Scala 3。
下面的代码
// monad defined for Option
given Monad3[Option] with {
def flatMap_[A, B](ma: Option[A])(fm: A => Option[B]): Option[B] = ???
def return_[A](a: A): Option[A] = ???
}
extension[M[] : Monad3, A] (cont: M[A])(using monad: Monad3[M]) {
def flatMap[B](f: A => M[B]): M[B] = monad.flatMap_(cont)(f)
}
extension[M[] : Monad3, A] (contCont: M[M[A]])(using monad: Monad3[M]) {
def join(): M[A] = monad.join(contCont)
}
// test
val flattenedOpt = Option(Option("hello!")).join_()
println(flattenedOpt)
适用于我。
__问题__:
我如何修改帮助扩展的签名,以便下面的具有子类型的代码也能正常工作?问题涉及 Scala 3 语法,与单子、库等无关...
val flattenedOpt = Some(Some("hello!")).join_()
是否与类型界限有关?
谢谢
英文:
Learning Scala 3.
below code
// monad defined for Option
given Monad3[Option] with {
def flatMap_[A, B](ma: Option[A])(fm: A => Option[B]): Option[B] = ???
def return_[A](a: A): Option[A] = ???
}
extension[M[_] : Monad3, A] (cont: M[A])(using monad: Monad3[M]) {
def flatMap_[B](f: A => M[B]): M[B] = monad.flatMap_(cont)(f)
}
extension[M[_] : Monad3, A] (contCont: M[M[A]])(using monad: Monad3[M]) {
def join_(): M[A] = monad.join(contCont)
}
// test
val flattenedOpt = Option(Option("hello!")).join_()
println(flattenedOpt)
works for me.
Question:
how do I modify signature of the helper extension for join so the below code with subtypes also works? Question is about Scala 3 syntax, not about monads, libraries, etc...
val flattenedOpt = Some(Some("hello!")).join_()
Is it smth with type bounds?
thanks
答案1
得分: 3
以下是翻译好的内容:
问题是关于Scala 3的语法,不涉及单子、库等等...
嗯,问题确实是关于单子,而不是Scala 3的语法等等。您可以为Option
和Some
分别定义Monad
的实例
given Monad3[Option] with
def flatMap_[A, B](ma: Option[A])(fm: A => Option[B]): Option[B] = ma match
case Some(a) => fm(a)
case None => None
def return_[A](a: A): Option[A] = Some(a)
given Monad3[Some] with
def flatMap_[A, B](ma: Some[A])(fm: A => Some[B]): Some[B] = fm(ma.value)
def return_[A](a: A): Some[A] = Some(a)
但一般情况下,您不能从类型的实例派生子类型或超类型的实例。这是因为Monad
只能在M[_]
方面是不变的,不能协变(Monad[+M[_]]
)或逆变(Monad[-M[_]]
)。
https://stackoverflow.com/questions/57749544/cats-instances-for-some-and-none-et-al
还有一些ADTs / GADTs(代数数据类型、封闭特质层次结构)使用类型构造器参数化,可以为类型类Functor
、Traversable
、Foldable
派生通用实例,但不能为Monad
或Applicative
派生,因为没有一种标准方法来展开任意数据类型。
https://stackoverflow.com/questions/18861231/why-is-there-no-xderiveapplicative-extension
https://stackoverflow.com/questions/60457433/haskell-automatic-monad-instance
如果您真正只是询问关于Scala 3类型界限的语法,那么与Scala 2相同,即def foo[A <: B : TC]
(对于类型类TC[A]
),def foo[A[x] <: B[x] : TC]
(对于类型类TC[A[_]]
)。
您不应该写成extension[M[_]: Monad3, A](cont: M[A])(using monad: Monad3[M])
。它应该是隐式参数extension[M[_], A](cont: M[A])(using monad: Monad3[M])
或上下文界定extension[M[_]: Monad3, A](cont: M[A])
。
英文:
> Question is about Scala 3 syntax, not about monads, libraries, etc...
Well, the thing is that the question is exactly about monads, not Scala 3 syntax etc. You can define separate instances of Monad
for Option
and Some
given Monad3[Option] with
def flatMap_[A, B](ma: Option[A])(fm: A => Option[B]): Option[B] = ma match
case Some(a) => fm(a)
case None => None
def return_[A](a: A): Option[A] = Some(a)
given Monad3[Some] with
def flatMap_[A, B](ma: Some[A])(fm: A => Some[B]): Some[B] = fm(ma.value)
def return_[A](a: A): Some[A] = Some(a)
But generally you can't derive an instance for subtype or supertype from an instance for a type. That's because Monad
can be only invariant with respect to M[_]
, not covariant (Monad[+M[_]]
) or contravariant (Monad[-M[_]]
).
https://stackoverflow.com/questions/57749544/cats-instances-for-some-and-none-et-al
Also for some ADTs / GADTs (case classes, sealed-trait hierarchies) parametrized with a type constructor, generic derivation is possible for the type classes Functor
, Traversable
, Foldable
but not for Monad
or Applicative
because there is no standard way to flatten arbitrary data types.
https://stackoverflow.com/questions/18861231/why-is-there-no-xderiveapplicative-extension
https://stackoverflow.com/questions/60457433/haskell-automatic-monad-instance
If you're really asking just about Scala 3 syntax for type bounds, it's the same as in Scala 2 i.e. def foo[A <: B : TC]
(for a type class TC[A]
), def foo[A[x] <: B[x] : TC]
(for a type class TC[A[_]]
).
You shouldn't write extension[M[_]: Monad3, A](cont: M[A])(using monad: Monad3[M])
. It should be either implicit parameter extension[M[_], A](cont: M[A])(using monad: Monad3[M])
or context bound extension[M[_]: Monad3, A](cont: M[A])
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论