gpt4 book ai didi

scala - 返回类型取决于 Scala 中的输入类型的通用函数?

转载 作者:行者123 更新时间:2023-12-04 02:30:46 26 4
gpt4 key购买 nike

我正在尝试编译这段代码:

import cats.effect.IO

sealed trait Shape {
val x: Int
}

case class Square(x: Int, y: Int) extends Shape
case class Cube(x: Int, y: Int, z: Int) extends Shape

def modifyShape[S <: Shape](shape: S): IO[S] = shape match {
case s: Square => IO(s.copy(y = 5))
case c: Cube => IO(c.copy(z = 5))
}

当我尝试编译这段代码时出现错误:

type mismatch;
found : Square
required: S
case s: Square => IO(s.copy(y = 5))

如何使这段代码工作?

更新:
阅读评论和文章后,我尝试像这样使用 F-bound:

sealed trait Shape[A <: Shape[A]] { this: A =>
val x: Int
}

case class Square(x: Int, y: Int) extends Shape[Square]
case class Cube(x: Int, y: Int, z: Int) extends Shape[Cube]

def modifyShape[S <: Shape[S]](shape: S): IO[S] = shape match {
case s: Square => IO(s.copy(y = 5))
case c: Cube => IO(c.copy(z = 5))
}

但是我好像漏掉了什么。这仍然不起作用。

最佳答案

现在modifyShape的 body

shape match {
case s: Square => IO(s.copy(y = 5))
case c: Cube => IO(c.copy(z = 5))
}

只是不满足其签名

def modifyShape[S <: Shape](shape: S): IO[S] 

在这里查看详细信息:

Why can't I return a concrete subtype of A if a generic subtype of A is declared as return parameter?

Type mismatch on abstract type used in pattern matching

foo[S <: Shape]意味着 foo必须为任何工作S那是 Shape 的子类型.假设我取 S := Shape with SomeTrait , 你不返回 IO[Shape with SomeTrait] .

尝试使用 F 有界类型参数的 GADT

sealed trait Shape[S <: Shape[S]] { this: S =>
val x: Int
def modifyShape: IO[S]
}

case class Square(x: Int, y: Int) extends Shape[Square] {
override def modifyShape: IO[Square] = IO(this.copy(y = 5))
}
case class Cube(x: Int, y: Int, z: Int) extends Shape[Cube] {
override def modifyShape: IO[Cube] = IO(this.copy(z = 5))
}

def modifyShape[S <: Shape[S]](shape: S): IO[S] = shape.modifyShape

https://tpolecat.github.io/2015/04/29/f-bounds.html (@LuisMiguelMejíaSuárez 提醒链接)

或具有 F 有界类型成员的 GADT

sealed trait Shape { self =>
val x: Int
type S >: self.type <: Shape { type S = self.S }
def modifyShape: IO[S]
}

case class Square(x: Int, y: Int) extends Shape {
override type S = Square
override def modifyShape: IO[Square] = IO(this.copy(y = 5))
}
case class Cube(x: Int, y: Int, z: Int) extends Shape {
override type S = Cube
override def modifyShape: IO[Cube] = IO(this.copy(z = 5))
}

def modifyShape[_S <: Shape { type S = _S}](shape: _S): IO[_S] = shape.modifyShape
// or
// def modifyShape(shape: Shape): IO[shape.S] = shape.modifyShape

或 GADT(无 F-bound)

(详见@MatthiasBerndtanswer和我对它的评论,此代码部分来自他的回答)

sealed trait Shape[A] {
val x: Int
}

case class Square(x: Int, y: Int) extends Shape[Square]
case class Cube(x: Int, y: Int, z: Int) extends Shape[Cube]

def modifyShape[S](shape: Shape[S]): IO[S] = shape match {
case s: Square => IO(s.copy(y = 5))
case c: Cube => IO(c.copy(z = 5))
}

或者ADT+反射

sealed trait Shape {
val x: Int
}

case class Square(x: Int, y: Int) extends Shape
case class Cube(x: Int, y: Int, z: Int) extends Shape

import scala.reflect.runtime.universe._

def modifyShape[S <: Shape : TypeTag](shape: S): IO[S] = (shape match {
case s: Square if typeOf[S] <:< typeOf[Square] => IO(s.copy(y = 5))
case c: Cube if typeOf[S] <:< typeOf[Cube] => IO(c.copy(z = 5))
}).asInstanceOf[IO[S]]

或ADT + 类型类

sealed trait Shape {
val x: Int
}

case class Square(x: Int, y: Int) extends Shape
case class Cube(x: Int, y: Int, z: Int) extends Shape

trait ModifyShape[S <: Shape] {
def modifyShape(s: S): IO[S]
}
object ModifyShape {
implicit val squareModifyShape: ModifyShape[Square] = s => IO(s.copy(y = 5))
implicit val cubeModifyShape: ModifyShape[Cube] = c => IO(c.copy(z = 5))
}

def modifyShape[S <: Shape](shape: S)(implicit ms: ModifyShape[S]): IO[S] =
ms.modifyShape(shape)

或 ADT + 磁铁

sealed trait Shape {
val x: Int
}

case class Square(x: Int, y: Int) extends Shape
case class Cube(x: Int, y: Int, z: Int) extends Shape

import scala.language.implicitConversions

trait ModifyShape {
type Out
def modifyShape(): Out
}
object ModifyShape {
implicit def fromSquare(s: Square): ModifyShape { type Out = IO[Square] } = new ModifyShape {
override type Out = IO[Square]
override def modifyShape(): IO[Square] = IO(s.copy(y = 5))
}
implicit def fromCube(c: Cube): ModifyShape { type Out = IO[Cube] } = new ModifyShape {
override type Out = IO[Cube]
override def modifyShape(): IO[Cube] = IO(c.copy(z = 5))
}
}

def modifyShape(shape: ModifyShape): shape.Out = shape.modifyShape()

关于scala - 返回类型取决于 Scala 中的输入类型的通用函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64318180/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com