Scala 3. 为类和所有子类定义扩展

huangapple go评论64阅读模式
英文:

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的语法等等。您可以为OptionSome分别定义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/47181109/calling-generic-function-with-functor-using-subclass-cats-scalaz

https://stackoverflow.com/questions/48545028/why-can-find-functor-instance-for-tree-but-not-for-branch-or-leaf

https://stackoverflow.com/questions/57749544/cats-instances-for-some-and-none-et-al

https://stackoverflow.com/questions/75299469/can-i-get-the-compiler-to-realize-there-is-an-applicative-for-the-superclass

还有一些ADTs / GADTs(代数数据类型、封闭特质层次结构)使用类型构造器参数化,可以为类型类FunctorTraversableFoldable派生通用实例,但不能为MonadApplicative派生,因为没有一种标准方法来展开任意数据类型。

https://stackoverflow.com/questions/29787252/why-there-is-no-way-to-derive-applicative-functors-in-haskell

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 =&gt; Option[B]): Option[B] = ma match
    case Some(a) =&gt; fm(a)
    case None =&gt; None
  def return_[A](a: A): Option[A] = Some(a)

given Monad3[Some] with
  def flatMap_[A, B](ma: Some[A])(fm: A =&gt; 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/47181109/calling-generic-function-with-functor-using-subclass-cats-scalaz

https://stackoverflow.com/questions/48545028/why-can-find-functor-instance-for-tree-but-not-for-branch-or-leaf

https://stackoverflow.com/questions/57749544/cats-instances-for-some-and-none-et-al

https://stackoverflow.com/questions/75299469/can-i-get-the-compiler-to-realize-there-is-an-applicative-for-the-superclass

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/29787252/why-there-is-no-way-to-derive-applicative-functors-in-haskell

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 &lt;: B : TC] (for a type class TC[A]), def foo[A[x] &lt;: 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]).

huangapple
  • 本文由 发表于 2023年2月24日 03:15:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/75549363.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定