英文:
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]).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论